Question

I have a lot of classes with a typedef of std::function<void(PARAMS)> where PARAMS is specific to each class. I need to specialize based on the number of parameters and the first parameter's type. I'd like to use boost::function_traits for this, but in order to use it, I need to have the raw function type of the std::function in question.

For example, given std::function<void(int,int)>, I want to retrieve void(int,int).

Is there any way to extract the native type in a portable manner? As a side note, I do not have access to C++11 features.

Was it helpful?

Solution

To get the function type, you can use partial specialization:

template <typename T>
struct Detect;

template <typename F>
struct Detect<std::function<F>> {
  typedef F Result;
};

Now when you get an unknown std::function<?> type T, you just use

typename Detect<T>::Result

(you might want do define Result as F *, as some contexts (e.g., field types) only allow pointer-to-function, and not bare function types.

Edit:

To specialize on the number of arguments and the type of the first one, you would need either C++11 variadic templates

template <typename T>
struct Detect;

template <typename R, typename A, typename... As>
struct Detect<std::function<R(A,As...)>> {
  static constexpr auto numargs = 1 + sizeof...(As);
  typedef R Result;
  typedef A FirstArg;
};

or to code the equivalent of the above, using a separate specialization for each possible number of arguments:

template <typename R, typename A1>
struct Detect<std::function<R(A1)>> {
  enum { numargs = 1 };
  typedef R Result;
  typedef A1 FirstArg;
};

template <typename R, typename A1, typename A2>
struct Detect<std::function<R(A1,A2)>> {
  enum { numargs = 2 };
  ...
};

...

OTHER TIPS

std::function contains result_type, argument_type for unary functions, and first_argument_type and second_argument_type for binary functions. You can extract these. For n-ary functions defined with variadic templates, I don't think there is a std::tuple containing all the arguments.

If you want your own traits class:

template<typename Fun>
struct function_traits;

template<typename R, typename... Args>
struct function_traits<std::function<R(Args...)>
{
    typedef R return_type;
    typedef std::tuple<Args...> arguments_type;
};

It should be simple enough to create a metafunction to extract the T in the boost::function<T>

template<typename T>
struct func_extractor

template<typename T>
struct func_extractor<boost::function<T> >
{
   typedef T type;
};

int main()
{
    typedef boost::function<void(int, int)> func_type1; 
    typedef func_extractor<func_type1>::type extracted_type;
    typedef boost::function<extracted_type> func_type2;
    std::cout << boost::is_same<func_type1, func_type2>::value << std::endl;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top