I have a class, Delegate
, declared like this:
template<typename T> class Delegate;
template<typename R, typename... Args>
class Delegate<R(Args...)>
{ /*...*/ };
It can be instantiated for a function returning a ReturnType
and taking no arguments as a Delegate<ReturnType()>
. I've run into an issue that requires me to specialize the class' ()
operator for this case, but haven't been able to figure out how to coerce the compiler doing so without a compiler error.
I have the following function:
template <typename R, typename... Args>
R Delegate<R(Args...)>::operator()(Args... args)
{ /*...*/ }
Adding the following specialization, I get an an error saying invalid use of incomplete type 'class Delegate<R()>'
:
template <typename R>
R Delegate<R()>::operator()()
{ /*...*/ }
but I can't simply replace Args...
with void
either, as far as I've been able to tell... What is the proper procedure here, and (if this question applies and you are feeling extra helpful) why?
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:
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
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
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With