Your attempt with using R Delegate<R()>::operator()()
to specialize even more the member function of a partial specialization of a class template fails due to ยง14.5.5.3 [temp.class.spec.mfunc]:
1 The template parameter list of a member of a class template partial specialization shall match the template parameter list of the class template partial specialization.
In other words:
template <typename R>
R Delegate<R()>::operator()() { /**/ }
is actually a specialization of operator()
of your primary template:
template <typename T>
class Delegate;
and since it's an incomplete type, you end up with the error. The possible workarounds are:
Option #1
Specialize the entire class and reimplement all the members of that class:
template <typename T>
class Delegate;
template <typename R, typename... Args> // partial specialization for non-empty Args
class Delegate<R(Args...)>
{
R operator()(Args...) { return {}; }
};
template <typename R> // partial specialization for empty Args
class Delegate<R()>
{
R operator()() { return {}; }
};
DEMO 1
Option #2
Use a one more delegate class that is specialized:
#include <utility>
template <typename T>
struct Impl;
template <typename R, typename... Args>
struct Impl<R(Args...)>
{
static R call(Args&&...) { return {}; }
};
template <typename R>
struct Impl<R()>
{
static R call() { return {}; }
};
template <typename T>
class Delegate;
template <typename R, typename... Args>
class Delegate<R(Args...)>
{
R operator()(Args... args)
{
return Impl<R(Args...)>::call(std::forward<Args>(args)...);
}
};
DEMO 2
Option #3
Use some ugly SFINAE:
#include <type_traits>
template <typename T>
class Delegate;
template <typename R, typename... Args>
class Delegate<R(Args...)>
{
template <typename T = R>
typename std::enable_if<sizeof...(Args) != 0 && std::is_same<T,R>{}, R>::type
operator()(Args...) { return {}; }
template <typename T = R>
typename std::enable_if<sizeof...(Args) == 0 && std::is_same<T,R>{}, R>::type
operator()() { return {}; }
};
DEMO 3
Option #4
Inherit from a specialized class template, possibly utilizing the CRTP idiom:
template <typename T>
class Delegate;
template <typename T>
struct Base;
template <typename R, typename... Args>
struct Base<Delegate<R(Args...)>>
{
R operator()(Args...)
{
Delegate<R(Args...)>* that = static_cast<Delegate<R(Args...)>*>(this);
return {};
}
};
template <typename R>
struct Base<Delegate<R()>>
{
R operator()()
{
Delegate<R()>* that = static_cast<Delegate<R()>*>(this);
return {};
}
};
template <typename R, typename... Args>
class Delegate<R(Args...)> : public Base<Delegate<R(Args...)>>
{
friend struct Base<Delegate<R(Args...)>>;
};
DEMO 4