I maintain an open-source lockless threading library designed for high speed parallel loop unrolling which is used in a couple commercial video games. It has incredibly low-overhead, around 8 clocks for creating a message and around 500 (per thread, including latency) for the entire dispatch and remote execute overhead. I say this first to explain why I don't simply use use std::function and bind.
The library packages a function call and the arguments to the function call in a message (of type Functor<>). Then calls it remotely with copies of the arguments.
I have recently rewritten the library to package remote calls using STL style template meta programming rather than the dated C style macros it originally used. Amazingly this only increased the overhead by two ticks but I cannot figure out how to create a packaging function that takes both lambdas and function pointers.
Desired Usage:
CreateFunctor([](int a, int b){doSomething(a, b)}, 1, 2);
or
CreateFunctor(&doSomething, 1, 2);
Currently I have to divide these cases into two separate functions, (CreateFunctor and CreateFunctorLambda). If I could combine them I would be able to merge my packaging and dispatching stages into one neat function call and simplify the API.
The problem is that the code for deducing the arguments of a lambda cannot seem to share a template override with the code for deducing the arguments of a function. I've tried using enable_if and it still executes the ::* portion of the lambda version and causes compiler errors with function pointers.
Relevant Snippet:
template <typename... Arguments>
inline Functor<Arguments...> CreateFunctor(void(*func)(Arguments...))
{
return Functor<Arguments...>(func);
};
template <typename... Arguments>
inline Functor<Arguments...> CreateFunctor(void(*func)(Arguments...), Arguments ... arg)
{
Functor<Arguments...> ret(func);
ret.Set(arg...);
return ret;
};
// template to grab function type that lambda can be cast to
// from http://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda
template <class T>
struct deduce_lambda_arguments
: public deduce_lambda_arguments<typename std::enable_if<std::is_class<T>::value, decltype(&T::operator())>::type>
{};
template <class ClassType, typename... Args>
struct deduce_lambda_arguments<void(ClassType::*)(Args...) const>
// we specialize for pointers to member function
{
typedef void(*pointer_cast_type)(Args...);
typedef Functor<Args...> functor_type;
};
template <typename F, typename... Args>
inline auto CreateFunctorLambda(F f, Args... arg) -> typename deduce_lambda_arguments<F>::functor_type
{
deduce_lambda_arguments<F>::functor_type ret((deduce_lambda_arguments<F>::pointer_cast_type) f);
ret.Set(arg...);
return ret;
};
template <typename F>
inline auto CreateFunctorLambda(F f) -> typename deduce_lambda_arguments<F>::functor_type
{
return deduce_lambda_arguments<F>::functor_type((deduce_lambda_arguments<F>::pointer_cast_type) f);
};