As has been noted in other answers, there is such a thing as function template parameters. However, sometimes it is desirable for the template parameter to be a type. This is especially useful with other kinds of template metaprogramming, e.g. to make a list of functions.
The following code allows you to wrap functions in types. There are different variants of the WRAP_FUNC
macro for wrapping a function. The suffix-less one is for use outside of templates, the _T
variant is for use within templates, and the _TI
variant is for inheriting within templates (see below).
Note that in order to work with references, std::forward
is used. Also, it must be used as written, with another parameter pack, CallArgs
, for the types of arguments which call()
is called with, as opposed to Args
, which are the argument types for the given function.
#include <utility>
#include <stdio.h>
// This goes into a header.
template <typename R, typename... Args>
struct Helper {
template <R (*Func) (Args...)>
struct Wrapper {
template <typename... CallArgs>
static R call (CallArgs && ... args)
{
return Func(std::forward<CallArgs>(args)...);
}
};
};
template <typename R, typename... Args>
struct Helper<R, Args...> MakeHelper (R (*func) (Args...));
#define WRAP_FUNC(func) decltype(MakeHelper(func))::Wrapper<func>
#define WRAP_FUNC_T(func) typename decltype(MakeHelper(func))::template Wrapper<func>
#define WRAP_FUNC_TI(func) decltype(MakeHelper(func))::template Wrapper<func>
// Let's try it out.
static double test_func (int x, double y)
{
return x + y;
}
using TestFunc = WRAP_FUNC(test_func);
template <typename Func>
static void CallFunc ()
{
double r = Func::call(4, 6.0);
printf("%f\n", r);
}
int main ()
{
CallFunc<TestFunc>();
}
If the function can only be defined after being passed to the class that needs it (because it itself calls to the class that calls it and we don't want to separate its definition and declaration), inheritance can be used to work around the circular dependency. Here, the _TI
form of the macro needs to be used if this is within a template.
template <.....>
class Qux {
struct CallbackFunc;
using MyFoo = Foo<CallbackFunc>;
static void callback_func ()
{
// Foo calls us but we call Foo!
MyFoo::bar();
}
struct CallbackFunc : public WRAP_FUNC_TI(callback_func) {};
};