Is it possible to extract argument types from the signature of a member function (Functor member) for use in a template?

Suppose you have a functor:

struct MyFunctor { bool operator ()( int value ) { return true; } }; 

Is it possible to get the type of an argument-member-member for use in your template? The following is the use of this mythical functionality:

 template < typename FunctorType > bool doIt( FunctorType functor, typename FunctorType::operator()::arg1 arg ) { return functor( arg ); } 

Is there any valid syntax that will replace my mythical FunctorType::operator()::arg1 ?

+4
source share
4 answers

No no. The most elegant way to do this is either to require your functors to provide a typedef for the type of the argument, or to introduce a feature class. The latter is useful if you want your template to work with functors and functions.

Alternatively, you can simply enter an argument of the type of the second template parameter:

 template < typename FunctorType, class ArgumentType > bool doIt( FunctorType functor, ArgumentType arg ) { return functor( arg ); } 

The compiler will still complain if the ArgumentType does not match the type required by the functor.

+4
source

If you know that the element is a functor, you can simply take its operator() , for example:

 #include <iostream> template <unsigned Idx, typename... T> struct pick { static_assert(Idx < sizeof...(T), "cannot index past end of list"); }; template <typename T, typename... TRest> struct pick<0U, T, TRest...> { typedef T result; }; template <unsigned Idx, typename T, typename... TRest> struct pick<Idx, T, TRest...> { typedef typename pick<Idx-1, TRest...>::result result; }; template <typename Func> struct func_traits; template <typename TObj, typename R, typename... TArgs> struct func_traits<R (TObj::*)(TArgs...)> { typedef R result_type; template <unsigned Idx> struct argument { typedef typename pick<Idx, TArgs...>::result type; }; }; template <typename Func, typename Traits = func_traits<Func>, typename R = typename Traits::result_type, typename Arg0 = typename Traits::template argument<0>::type, typename Arg1 = typename Traits::template argument<1>::type > void foo(Func f) { std::cout << __PRETTY_FUNCTION__ << std::endl; }; struct thing { void operator()(long, int*) { } }; int main() { foo(&thing::operator()); } 

For me, this program prints:

 void foo(Func) [with Func = void (thing::*)(long int, int*), Traits = func_traits<void (thing::*)(long int, int*)>, R = void, Arg0 = long int, Arg1 = int*] 

The key point is that Arg0 and Arg1 are long and int* respectively.

+5
source

You can do it in C ++ 0x

 template <typename... Args> struct Function { typedef std :: tuple <Args...> args; void call () (Args... args); } template <typename... Args> void do_it (Function<Args...>::args:: SOMETHING :: type t, Args... args) { something (t) Function <Args...> :: call (args...); } 
+3
source

Here I am giving a C ++ 11 update for @ BjörnPollex's answer (correct).

When returning the question, you want to specify the second doIt argument explicitly mainly to limit what can be passed. In C ++ 11, you can specify this restriction without knowing explicitly the type of the functor argument (which is not correct if the overloaded functor is anyway).

 template < typename FunctorType, class ArgumentType > auto doIt( FunctorType functor, ArgumentType arg ) -> decltype(bool(functor(arg))) { return functor( arg ); } 

(conversion to bool may not even be necessary, I put it here because it seems like you really want the return type to be bool ).

This doIt (template) function accepts any argument that is possibly compatible with the functor argument (and also converts to bool ). If the passed argument is incompatible, the function will not exist at all and will create an elegant compiler error "doIt function not found".

You can take one more step, using perfect forward, to make doIt exactly equivalent to functor(arg) :

 template < typename F, class A > auto doIt( F&& f, A&& a ) -> decltype(bool(std::forward<F>(f)(std::forward<A>(a)))) { return std::forward<F>(f)( std::forward<A>(a) ); } 
+2
source

All Articles