I have a templated function wrapper that I am attempting to update to C++11 syntax (variadic paremeters).
My issue is that I am caught in a "catch 22" where ' Args...
' must be the last template parameter, but at the same time, cannot be defined after the function pointer template parameter.
Any idea if this can actually be solved?
template <typename... Args, void(*Function)(Args...)>
class function
{
public:
void operator ()(Args... args) const
{
(*Function)(std::forward<Args...>(args...));
}
};
A possible way is to use the template specialization
template <typename>
struct myFunc;
template <typename R, typename ... Args>
struct myFunc<R(*)(Args...)>
{
// ...
};
but, this way, you intercept (as template parameter) the type of the function pointer, not the function pointer itself; so you have to pass the function pointer in some way (constructor?).
Also observe that, if you want to use perfect forwarding, you have to transform operator()
in a template method receiving arguments as universal references ( &&
).
Something as follows
template <typename ... As>
R operator() (As && ... args) const
{
return fun(std::forward<As>(args)...);
}
where fun
is a pointer of type R(*)(Args...)
.
The following is a full compiling example
#include <iostream>
#include <utility>
int foo (int, long)
{ return 42; }
template <typename>
struct myFunc;
template <typename R, typename ... Args>
struct myFunc<R(*)(Args...)>
{
using funPnt = R(*)(Args...);
funPnt fun = nullptr;
myFunc (funPnt f0) : fun{f0}
{ }
template <typename ... As>
R operator() (As && ... args) const
{
return fun(std::forward<As>(args)...);
}
};
int main ()
{
myFunc<decltype(&foo)> mf0{&foo};
std::cout << mf0(1, 2l) << std::endl;
}
If you really want the pointer function as template parameter (but, this way, every function determine a different type; this can be a good or a bad thing according to your needs), you can write the myFunc
struct receiving before a type (the same pointer type) and then a value of that type.
So
template <typename T, T>
struct myFunc;
template <typename R, typename ... Args, R(*Func)(Args...)>
struct myFunc<R(*)(Args...), Func>
{
template <typename ... As>
R operator() (As && ... args) const
{
return Func(std::forward<As>(args)...);
}
};
that can be declared
myFunc<decltype(&foo), foo> mf0;
If you can use C++17, you can simplify using auto
for type of template values; so you can avoid the type
template <auto>
struct myFunc;
template <typename R, typename ... Args, R(*Func)(Args...)>
struct myFunc<Func>
{
template <typename ... As>
R operator() (As && ... args) const
{
return Func(std::forward<As>(args)...);
}
};
and you can create a myFunc
object as follows
myFunc<&foo> mf0;
Addendum: if you can use C++17, you can define a deduction guide for the first example (pointer as member, not as template value parameter)
template <typename R, typename ... Args>
myFunc (R(*)(Args...)) -> myFunc<R(*)(Args...)>;
so, instead of
myFunc<decltype(&foo)> mf0{&foo};
you can simply write
myFunc mf0{&foo};
Off Topic: I hope that you know that you're reinventing the wheel. As suggested by NathanOliver, the standard provide std::function
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.