Reputation: 7502
I am trying to build a static wrapper function that will be able to call member and and non-member function pointers.
What I have come up with is as follows -
template <typename Derived>
struct CallAny {
template<typename F> using ReturnType = typename std::function<typename std::remove_pointer<F>::type>::result_type;
template<typename F, bool IsMember, typename... Args>
static ReturnType<F> function_wrapper(Derived* obj, F func, Args... args);
template<typename F, typename... Args>
static ReturnType<F> function_wrapper<F, true, Args...>(Derived *obj, F func, Args... args) {
return obj->*func(args...);
}
template<typename F, typename... Args>
static ReturnType<F> function_wrapper<F, false, Args...>(Derived *obj, F func, Args... args) {
return func(args...);
}
};
struct CallAnyDerived : public CallAny<CallAnyDerived> {};
Here F
is a function pointer type that has to be called with arguments given in Args...
. F
might be a C-style function pointer or a member of class Derived
which inherits from CallAny
.
When I try to compile this code, I get an error saying -
XXXXXXXXXXX: error: function template partial specialization ‘fucntion_wrapper<F, true, Args ...>’ is not allowed
static ReturnType<F> function_wrapper<F, true, Args...>(Derived *obj, F func, Args... args) {
^
XXXXXXXXXXX: error: function template partial specialization ‘fucntion_wrapper<F, false, Args ...>’ is not allowed
static ReturnType<F> function_wrapper<F, false, Args...>(Derived *obj, F func, Args... args) {
^
How do I fix this?
Upvotes: 1
Views: 116
Reputation: 36802
In general you cannot partially specialize a function. The way around that is to create a helper struct with something like a static R call(...)
, and partially specialize the helper struct instead.
In this case you don't need template specialization at all, you can use overloading
template <typename Derived>
struct CallAny {
template<typename F> using ReturnType = typename std::function<typename std::remove_pointer<F>::type>::result_type;
// takes pointer to member function
template<typename R, typename... Ts, typename... Args>
static R function_wrapper(Derived* obj, R (Derived::*func)(Ts...), Args... args) {
return obj->*func(args...);
}
// takes everything else
template<typename F, typename... Args>
static ReturnType<F> function_wrapper(Derived *obj, F func, Args... args) {
return func(args...);
}
};
Upvotes: 4
Reputation: 217255
You may use SFINAE:
template <typename Derived>
struct CallAny {
template<typename F, typename... Args>
static
auto
function_wrapper(Derived* obj, F func, Args&&... args)
-> std::enable_if_t<
std::is_member_function_pointer<F>::value,
decltype((obj->func)(std::forward<Args>(args)...))>
{
return (obj->func)(std::forward<Args>(args)...);
}
template<typename F, typename... Args>
static
auto
function_wrapper(Derived* obj, F func, Args&&... args)
-> std::enable_if_t<
!std::is_member_function_pointer<F>::value,
decltype(func)(/*obj,*/std::forward<Args>(args)...))>
{
return func(/*obj,*/std::forward<Args>(args)...);
}
};
or tag dispatching:
template <typename Derived>
struct CallAny {
template<typename F, typename... Args>
static
auto
function_wrapper(Derived* obj, F func, Args&&... args)
{
return impl(std::is_member_function_pointer<F>{}, obj, func, std::forward<Args>(args)...);
}
template<typename F, typename... Args>
static
auto
impl(std::true_type, Derived* obj, F func, Args&&... args)
-> decltype((obj->func)(std::forward<Args>(args)...))
{
return (obj->func)(std::forward<Args>(args)...);
}
template<typename F, typename... Args>
static
auto
impl(std::true_type, Derived* obj, F func, Args&&... args)
-> decltype(func)(/*obj,*/std::forward<Args>(args)...))>
{
return func(/*obj,*/std::forward<Args>(args)...);
}
};
Upvotes: 1