I'm trying to implement tuples with template metaprogramming, but am having problems with the indexing function get. The implementation of Tuple type is this:
template<typename A, typename... B>
class Tuple : Tuple<B...> {
private:
A val;
public:
using Base = Tuple<B...>;
Base* base() {
return static_cast<Base*>(this);
}
const Base* base() const {
return static_cast<const Base*>(this);
}
Tuple(A a, B... b): Base(b...), val(a) { }
A first() {
return val;
}
};
template<class A>
class Tuple<A> {
private:
A val;
public:
Tuple(A a): val{a} {}
A first() {
return val;
}
};
The implementation of get structure is:
template<int N, class... A>
struct get {
select<N,A...> operator()(Tuple<A...> t) {
return get<N-1>()(t.base());
}
};
template<class R, class... A>
struct get<0> {
R operator()(Tuple<R, A...> t) {
return t.first();
}
};
This is the error compiler is giving me:
tuple.cpp:53:8: error: partial specialization of 'get' does not use any of its template parameters
struct get<0> {
^
1 error generated.
Why am I getting this error? How can I correct it?
Note: select<N,A...> is a type function which selects type at Nth index from A.
Your get's primary template is:
template<int N, class... A>
struct get{ ... };
your get's partial specialization is:
template<class R, class... A>
struct get<0>{ ... };
The specialization is receiving a single template argument, i.e.: 0, but the primary template above takes two template parameters:
the non-type template parameter N.
the variadic type parameter A.
Besides, how can R be deduced?
Specializing get instead as:
template<class R, class... A>
struct get<0, R, A...>{ ... };
will make possible R to be deduced: it will be deduced to the type of the first element of the passed variadic argument. For example, in:
get<0, int, float, double> foo;
R will be deduced to int.
Maybe you have to partial specialize get as follows
template<class R, class... A>
struct get<0, R, A...> {
R operator()(Tuple<R, A...> t) {
return t.first();
}
};
I mean... get<0, R, A...>, not get<0>
But you have also to modify the main get to call the following call with the correct type list, so
template<int N, typename A0, typename ... As>
struct get {
auto operator()(Tuple<A0, As...> t) {
return get<N-1, As...>()(t.base());
}
};
Otherwise you can also demand the types management to a template version of the operator() and maintain only the int N value for get
template <int N>
struct get
{
template <typename Tpl>
auto operator() (Tpl t)
-> decltype( get<N-1>()(t.base()) )
{ return get<N-1>()(t.base()); }
};
template<>
struct get<0>
{
template <typename Tpl>
auto operator() (Tpl t)
-> decltype ( t.first() )
{ return t.first(); }
};
Starting from C++14 you can avoid the decltype() part.
Off topic suggestion: avoid the use of names that can collide with std namespace names.
Maybe myGet and myTuple instead of get and Tuple.
Otherwise you can put all in a personal namespace (so myNs::get and myNs::Tuple.
Related
I am trying to create a class template that expects a type and a function pointer as template parameters. The function pointer is expected to be a member function of the type passed in. I want the user of the class template to be able to pass in a void member function of the type passed in. That member function will then be called on instances of the type passed in every time a certain function of the class template is called. It's a bit hard to explain but it's supposed to work sort of like this:
template<Type, Function> // For the purpose of explaining it
class Foo
{
public:
template<Args... args>
void callOnAll(Args... args)
{
for(Type* ptr : ptrs_)
{
ptr->Function(std::forward<Args>(args)...);
}
}
private:
std::vector<Type*> ptrs_;
}
Assuming that something like this is possible (which I realize it might not be), the key would have to be getting the template parameters for the class right, and getting the update function right. This is what I've come up with but I still can't get it to work:
template<typename T, template<typename... Args> void(T::*func)(Args... args)>
class EngineSystem
{
public:
template<typename... Args>
void update(Args... args)
{
for (T* handler : handlers_)
{
((*handler).*func)(std::forward<Args>(args)...);
}
}
private:
std::vector<T*> handlers_;
};
The code above does not compile. It points me to the line where I declare the template parameters for the class, underlines void and says expected 'class' or 'typename'.
Is it clear what I'm trying to achieve, and is it possible?
C++ doesn't allow non-type template template parameters. That means you can't have a parameter-pack for your member-function pointer parameter.
Assuming you're using C++17 or newer, you can use an auto template parameter instead:
template<typename T, auto func>
public:
template<typename... Args>
void update(Args... args)
{
for (T* handler : handlers_)
{
(handler->*func)(std::forward<Args>(args)...);
}
}
private:
std::vector<T*> handlers_;
};
Live Demo
Technically that will accept any object for func, but assuming update is called, then (handler->*func)(std::forward<Args>(args)...) still has to be well-formed or compilation will fail.
If you want compilation to fail even if update never gets called, you could use some type traits and a static_assert (or some SFINAE hackery, if you need it) to ensure that func is actually a pointer to a member function of T:
template <typename T, typename U>
struct IsPointerToMemberOf : std::false_type {};
template <typename T, typename U>
struct IsPointerToMemberOf<T, U T::*> : std::true_type {};
template <typename T, typename U>
struct IsPointerToMemberFunctionOf
: std::integral_constant<
bool,
IsPointerToMemberOf<T, U>::value && std::is_member_function_pointer<U>::value
>
{};
template<typename T, auto func>
class EngineSystem
{
static_assert(IsPointerToMemberFunctionOf<T, decltype(func)>::value, "func must be a pointer to a member function of T");
//...
};
Live Demo
#include <iostream>
#include <vector>
template <typename T, typename... Args>
class EngineSystem
{
public:
EngineSystem(void(T::*fun)(Args... args)): fun(fun)
{
}
void update(Args... args)
{
for (T* handler : handlers_)
{
(handler->*fun)(std::forward<Args>(args)...);
}
}
void push(T* t){
handlers_.push_back(t);
}
private:
void(T::*fun)(Args... args);
std::vector<T*> handlers_;
};
struct A {
int x = 3;
void fn(int a, int b){
std::cout << a << b << x;
}
};
template <typename T, typename... Args>
auto makeEngine(void(T::*fun)(Args... args)){
return EngineSystem<T, Args...>(fun);
}
int main() {
EngineSystem<A, int, int> as(&A::fn);
// or deduce types automatically
auto es = makeEngine(&A::fn);
A a;
es.push(&a);
es.update(1,2);
return 0;
}
https://gcc.godbolt.org/z/Pcdf9K9nz
If I pass a lambda as a template parameter, what is the actual type of that parameter that is deduced? I have looked on the VS2017 debugger and the type of this lambda: [](int x) {return x; } is filename::__I2::int<lambda>(int).
The reason I am asking this is because I want to pass a lambda and then create an internal std::function from this. Note that this relates to this answer and why we have to use CTAD to construct an internal std::function instead of just passing the template parameter to a std::function.
As an example, I would like to do something like the following:
template<class Func, class... Args>
void createStdFunc(Func f, Args... args) {
std::function<Func> internalFunc = f; //this does not work
}
//usage
createStdFunc([](int x) {return x; }, 5);
However, this does not work, and I get the error 'initialising' cannot convert from 'Func' to 'std::function<Func>'. I am not sure how the types differ and how they have changed from passing into the function to initialising the std::function. Please note that I do know you can use CTAD from 2017 onwards, but was wondering what a solution for 2014 and before would have been?
In C++14 you can use return type deduction to figure out function signature, this implies that types of arguments passed into createStdFunc match:
template<class Func, class... Args>
void createStdFunc(Func f, Args... args) {
std::function<std::result_of_t<Func(Args...)> (Args...)> internalFunc{f}; //this does work
}
My way
#include <iostream>
#include <functional>
template <typename R, typename T, typename ... As>
constexpr std::function<R(As...)> getFuncType (R(T::*)(As...) const);
template <typename F, typename ... As>
void createStdFunc (F const & f, As ... as)
{
decltype(getFuncType(&F::operator())) internalFunc { f };
internalFunc(as...);
}
int main ()
{
createStdFunc([](int x) { std::cout << x << std::endl; }, 5);
}
Maybe also through a using
template <typename F>
using funcType = decltype(getFuncType(&F::operator()));
template <typename F, typename ... As>
void createStdFunc (F const & f, As ... as)
{
funcType<F> internalFunc { f };
internalFunc(as...);
}
The problem inside your code is that Func is not a function type. It's the type of the lambda. Lambdas compile down to something like this:
// equivalent:
// auto my_lambda = [](int v){ return v; };
struct /* unnamed */ {
auto operator()(int v) const { return v; }
} my_lambda;
The solution would be to extract the type of the operator() from the closure type:
using my_lambda_t = decltype(my_lambda);
// type: int(my_lambda_t::*)(int) const;
auto call_operator = &decltype(my_lambda_t)::operator();
Then, from the type of the operator(), you can deduce the type of the arguments and the return type:
template<typename>
struct extract_types {};
template<typename R, typename C, typename... Args>
struct extract_types<R(C::*)(Args...) const> {
using result = R;
using args_types = std::tuple<Args...>;
};
Generalized versions of this pattern is shipped in Boost.CallableTraits
You can write a simple trait to generalize callable types. If you handle both function pointers and anything with operator() (both const and non-const) you should be able to cover most use cases.
#include <tuple>
// For callable types
template<class T>
struct func_type : func_type<decltype(&T::operator())>{};
// For callable types' member functions (including `operator()`)
template<class T, class R, class ... Args >
struct func_type<R (T::*)(Args...) const> : func_type<R(*)(Args...)> {};
// For function pointers
template<class R, class ... Args >
struct func_type<R (*)(Args...)> {
using type = R(Args...);
using result = R;
using args = std::tuple<Args...>;
};
template<class T>
using func_type_t = typename func_type<T>::type;
func_type_t<T> should then give you a function type for most callable types T. Example uses :
#include <functional>
template<class Func, class... Args>
void createStdFunc(Func f, Args... args) {
// Replaced `Func` with `func_type_t<Func>`
std::function<func_type_t<Func>> internalFunc = f;
}
int foo(int x) { return x; }
struct bar {
int operator()(int x) { return x; };
};
int main()
{
// With lambda expression
createStdFunc([](int x) {return x; }, 5);
// With function pointer
createStdFunc(foo, 5);
// With std::function
std::function<int(int)> std_func = [](int x) {return x; };
createStdFunc(std_func, 5);
// With a functor
createStdFunc(bar{}, 5);
}
The std::function template expects as its argument a function type from which it infers the return and parameter type for the callable to wrap. The closure type of a lambda expression is a callable, but it's not a function type.
C++17 introduced deduction guides for std::function which allow the correct type to be deduced from any callable argument. Pre C++17, you could use a set of helper templates to deduce the correct type, for example:
template <typename F>
struct deduce_func_type_helper;
template <typename R, typename... Args>
struct deduce_func_type_helper<R(&)(Args...)>
{
using type = std::function<R(Args...)>;
};
template <typename R, typename... Args>
struct deduce_func_type_helper<R(*)(Args...)> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename C, typename R, typename... Args>
struct deduce_func_type_helper<R(C::*)(Args...)> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename C, typename R, typename... Args>
struct deduce_func_type_helper<R(C::*)(Args...) const> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename C, typename R, typename... Args>
struct deduce_func_type_helper<R(C::*)(Args...) volatile> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename F>
struct deduce_func_type_helper<F&> : deduce_func_type_helper<std::remove_cv_t<F>> {};
template <typename F>
struct deduce_func_type_helper<F&&> : deduce_func_type_helper<std::remove_cv_t<F>> {};
template <typename F>
struct deduce_func_type_helper : deduce_func_type_helper<decltype(&F::operator())> {};
template <typename F>
using func_type_t = typename deduce_func_type_helper<F>::type;
live example here
Note that above example is not complete; it's missing some specializations, e.g., for all possible combinations of const, volatile, and different ref qualifiers. So this can get quite verbose, you will probably want to go with C++17 if you can…
Suppose we have a class
template <int ... values>
struct foo;
now I have a function
template<typename foo_type, typename U>
void bar(foo_type a, U b);
where foo_type is basically foo. My issue is that, I do not want the variable a in the bar function. I want to be able to call the function like so
bar<foo<6,5,7,8,0>>(42);
but have all the parameters of foo available to me in bar. I tried changing the function to
template<template<int...> class foo_type, int ... args, typename U>
void bar(U b)
but this simply does not work. How can I do this? How can I change bar to the above way and still access the parameters in foo? Basically I want to do generic computation on those list at runtime
// within the body of bar
constexpr int[sizeof...(args)] = {args...};
where args is parameters of foo.
How opposed are you to having foo be an argument? Personally, I like having everything be an argument. Just wrap it in an empty type:
template <class T> struct tag_type { using type = T; };
template <class T> constexpr tag_type<T> tag{};
So that you can still template on the ints...:
template<int... Is, typename U>
void bar(tag_type<foo<Is...>> a, U b) {
constexpr int stuff[sizeof...(Is)] = {Is...};
// ...
}
Instead of calling bar<foo<6,5,7,8,0>>(42); you'd call bar(tag<foo<6,5,7,8,0>>, 42);, which is close enough.
To get exactly what you want, you can forward the former call to the latter:
namespace details {
template<int... Is, typename U>
void bar(tag_type<foo<Is...>> a, U b) {
constexpr int stuff[sizeof...(Is)] = {Is...};
// ...
}
}
template <typename foo_type, typename U>
void bar(U b) {
details::bar(tag<foo_type>, b);
}
And now it's the best of both worlds.
I believe, the question is about extracting template arguments from given foo type? If I am correct, here is the solution.
You will have to partially specialize a helper class, like following:
template <int ... values>
struct foo { };
template<class T>
struct bar_helper {};
template<int... values> struct bar_helper<foo<values...> > {
template<class T> static void bar(T ) {
// Use values... here
}
};
template<class foo_type, class U>
void bar(U b) {
bar_helper<foo_type>::bar(b);
}
void check() {
bar<foo<2, 3, 4, 5, 6> >(42);
}
I created a template class containing a std::function as a member the following way:
template<typename Ret, typename... Args>
class Foo
{
private:
std::function<Ret(Args...)> _func;
public:
Foo(const std::function<Ret(Args...)>& func):
_func(func)
{}
};
In order not to have to specify the arguments and return type of the passed function, I created some make_foo overloads:
template<typename Ret, typename... Args>
auto make_foo(Ret (&func)(Args...))
-> Foo<Ret, Args...>
{
return { std::function<Ret(Args...)>(func) };
}
template<typename Ret, typename... Args>
auto make_foo(const std::function<Ret(Args...)>& func)
-> Foo<Ret, Args...>
{
return { func };
}
However, I was unable to create a make_foo overload that takes a lambda as parameter:
template<typename Ret, typename... Args>
auto make_foo(??? func)
-> Foo<Ret, Args...>
{
return { std::function<Ret(Args...)>(func) };
}
I just can't find a way to have the return type and argument types automatically deduced from the lambda. Is there an idiomatic way to solve such a problem?
Ok, so I thought I would die, but I finally managed to do it ç_ç
First, I used the usual indices. Since I do not have the official ones, I used old indices I wrote some months ago:
template<std::size_t...>
struct indices {};
template<std::size_t N, std::size_t... Ind>
struct make_indices:
make_indices<N-1, N-1, Ind...>
{};
template<std::size_t... Ind>
struct make_indices<0, Ind...>:
indices<Ind...>
{};
Then, I used some function traits found somewhere on StackOverflow. They are nice, and I think that they are equivalent to the Boost library linked in the comments:
template<typename T>
struct function_traits:
function_traits<decltype(&T::operator())>
{};
template<typename C, typename Ret, typename... Args>
struct function_traits<Ret(C::*)(Args...) const>
{
enum { arity = sizeof...(Args) };
using result_type = Ret;
template<std::size_t N>
using arg = typename std::tuple_element<N, std::tuple<Args...>>::type;
};
Then, I was able to write a proper make_foo function and it implementation function, since both are required to use indices. Be careful, it's plain ugly:
template<typename Function, std::size_t... Ind>
auto make_foo_(Function&& func, indices<Ind...>)
-> Foo<
typename function_traits<typename std::remove_reference<Function>::type>::result_type,
typename function_traits<typename std::remove_reference<Function>::type>::template arg<Ind>...>
{
using Ret = typename function_traits<typename std::remove_reference<Function>::type>::result_type;
return { std::function<Ret(typename function_traits<typename std::remove_reference<Function>::type>::template arg<Ind>...)>(func) };
}
template<typename Function, typename Indices=make_indices<function_traits<typename std::remove_reference<Function>::type>::arity>>
auto make_foo(Function&& func)
-> decltype(make_foo_(std::forward<Function>(func), Indices()))
{
return make_foo_(std::forward<Function>(func), Indices());
}
The code is somehow ugly and unreadable, but it definitely works. Hope it does not rely on some implementation-defined behaviour now. Also, thanks all for your advice, it helped! :)
int main()
{
auto lambda = [](int i, float b, long c)
{
return long(i*10+b+c);
};
auto foo = make_foo(lambda);
std::cout << foo(5, 5.0, 2) << std::endl; // 57, it works!
}
And here is the live example :)
I have an example that works with mutable lambdas. I can't quite figure out how to get the CV member qualification right.
First, here's the function template we're after:
#include <functional>
template <typename R, typename ...Args>
void foo(std::function<R(Args...)> f)
{ }
Now we'll let a function template bar take an arbitrary lambda and call the right version of foo, by inspecting the type of the lambda's operator():
#include <type_traits>
template <typename> struct remove_member;
template <typename C, typename T>
struct remove_member<T C::*>
{ using type = T; };
template <typename F>
void bar(F f)
{
using ft = decltype(&F::operator());
foo(std::function<typename remove_member<ft>::type>(f));
}
Example:
int q;
bar([&](int a, int b) mutable -> int { q = a + b; return q / b; });
You can use normal, const lambdas with this modified trait, though I don't like having to spell the function type out:
template <typename C, typename R, typename ...Args>
struct remove_member<R (C::*)(Args...) const>
{ using type = R(Args...); };
I thought it might work with the original code if I use typename std::remove_cv<T>::type, but at least on GCC this doesn't work because of some strange __attribute__((const)) that's set on the lambda's operator type which seems to interfere with the template specialization.
I've written a traits class that lets me extract information about the arguments and type of a function or function object in C++0x (tested with gcc 4.5.0). The general case handles function objects:
template <typename F>
struct function_traits {
template <typename R, typename... A>
struct _internal { };
template <typename R, typename... A>
struct _internal<R (F::*)(A...)> {
// ...
};
typedef typename _internal<decltype(&F::operator())>::<<nested types go here>>;
};
Then I have a specialization for plain functions at global scope:
template <typename R, typename... A>
struct function_traits<R (*)(A...)> {
// ...
};
This works fine, I can pass a function into the template or a function object and it works properly:
template <typename F>
void foo(F f) {
typename function_traits<F>::whatever ...;
}
int f(int x) { ... }
foo(f);
What if, instead of passing a function or function object into foo, I want to pass a lambda expression?
foo([](int x) { ... });
The problem here is that neither specialization of function_traits<> applies. The C++0x draft says that the type of the expression is a "unique, unnamed, non-union class type". Demangling the result of calling typeid(...).name() on the expression gives me what appears to be gcc's internal naming convention for the lambda, main::{lambda(int)#1}, not something that syntactically represents a C++ typename.
In short, is there anything I can put into the template here:
template <typename R, typename... A>
struct function_traits<????> { ... }
that will allow this traits class to accept a lambda expression?
I think it is possible to specialize traits for lambdas and do pattern matching on the signature of the unnamed functor. Here is the code that works on g++ 4.5. Although it works, the pattern matching on lambda appears to be working contrary to the intuition. I've comments inline.
struct X
{
float operator () (float i) { return i*2; }
// If the following is enabled, program fails to compile
// mostly because of ambiguity reasons.
//double operator () (float i, double d) { return d*f; }
};
template <typename T>
struct function_traits // matches when T=X or T=lambda
// As expected, lambda creates a "unique, unnamed, non-union class type"
// so it matches here
{
// Here is what you are looking for. The type of the member operator()
// of the lambda is taken and mapped again on function_traits.
typedef typename function_traits<decltype(&T::operator())>::return_type return_type;
};
// matches for X::operator() but not of lambda::operator()
template <typename R, typename C, typename... A>
struct function_traits<R (C::*)(A...)>
{
typedef R return_type;
};
// I initially thought the above defined member function specialization of
// the trait will match lambdas::operator() because a lambda is a functor.
// It does not, however. Instead, it matches the one below.
// I wonder why? implementation defined?
template <typename R, typename... A>
struct function_traits<R (*)(A...)> // matches for lambda::operator()
{
typedef R return_type;
};
template <typename F>
typename function_traits<F>::return_type
foo(F f)
{
return f(10);
}
template <typename F>
typename function_traits<F>::return_type
bar(F f)
{
return f(5.0f, 100, 0.34);
}
int f(int x) { return x + x; }
int main(void)
{
foo(f);
foo(X());
bar([](float f, int l, double d){ return f+l+d; });
}
The void_t trick can help. How does `void_t` work?
Unless you have C++17, you'll need to include the definition of void_t:
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
Add an extra template argument to the original template, defaulted to void:
template <typename T, typename = void>
struct function_traits;
The traits object for simple functions is the same as you already have:
template <typename R, typename... A>
struct function_traits<R (*)(A...)>
{
using return_type = R;
using class_type = void;
using args_type = std:: tuple< A... >;
};
For non-const methods:
template <typename R, typename... A>
struct function_traits<R (C::*)(A...)>
{
using return_type = R;
using class_type = void;
using args_type = std:: tuple< A... >;
};
Don't forget const methods:
template <typename R, typename C, typename... A>
struct function_traits<R (C::*)(A...) const> // const
{
using return_type = R;
using class_type = C;
using args_type = std:: tuple< A... >;
};
Finally, the important trait. Given a class type, including lambda types, we want to forward from T to decltype(&T::operator()). We want to ensure that this trait is only available for types T for which ::operator() is available, and this is what void_t does for us. To enforce this constraint, we need to put &T::operator() into the trait signature somewhere, hence template <typename T> struct function_traits<T, void_t< decltype(&T::operator())
template <typename T>
struct function_traits<T, void_t< decltype(&T::operator()) > >
: public function_traits< decltype(&T::operator()) >
{
};
The operator() method in (non-mutable, non-generic) lambdas is const, which explains why we need the const template above.
But ultimately this is very restrictive. This won't work with generic lambdas, or objects with templated operator(). If you reconsider your design, you find find a different approach that is more flexible.
By delegating some of the work to a series of function templates instead of a class template, you can extract the relevant info.
First though, I should say that the relevant method is a const method, for a lambda (for a non-capturing, non-generic, non-mutable lambda). So you will not be able to tell the difference between a true lambda and this:
struct {
int operator() (int) const { return 7; }
} object_of_unnamed_name_and_with_suitable_method;
Therefore, I must assume that you don't want "special treatment" for lambdas, and you don't want to test if a type is a lambda type, and that instead you want to simply extract the return type, and the type of all arguments, for any object which is simple enough. By "simple enough" I mean, for example, that the operator() method is not itself a template. And, for bonus information, a boolean to tell us if an operator() method was present and used, as opposed to a plain old function.
// First, a convenient struct in which to store all the results:
template<bool is_method_, bool is_const_method_, typename C, typename R, typename ...Args>
struct function_traits_results {
constexpr static bool is_method = is_method_;
constexpr static bool is_const_method = is_const_method_;
typedef C class_type; // void for plain functions. Otherwise,
// the functor/lambda type
typedef R return_type;
typedef tuple<Args...> args_type_as_tuple;
};
// This will extract all the details from a method-signature:
template<typename>
struct intermediate_step;
template<typename R, typename C, typename ...Args>
struct intermediate_step<R (C::*) (Args...)> // non-const methods
: public function_traits_results<true, false, C, R, Args...>
{
};
template<typename R, typename C, typename ...Args>
struct intermediate_step<R (C::*) (Args...) const> // const methods
: public function_traits_results<true, true, C, R, Args...>
{
};
// These next two overloads do the initial task of separating
// plain function pointers for functors with ::operator()
template<typename R, typename ...Args>
function_traits_results<false, false, void, R, Args...>
function_traits_helper(R (*) (Args...) );
template<typename F, typename ..., typename MemberType = decltype(&F::operator()) >
intermediate_step<MemberType>
function_traits_helper(F);
// Finally, the actual `function_traits` struct, that delegates
// everything to the helper
template <typename T>
struct function_traits : public decltype(function_traits_helper( declval<T>() ) )
{
};