可变参数模板的部分模板特化,其中[Args ...]为空

时间:2014-11-18 05:27:33

标签: c++ c++11 variadic-templates partial-specialization

我有一个类Delegate,声明如下:

template<typename T> class Delegate;

template<typename R, typename... Args>
class Delegate<R(Args...)>
{ /*...*/ };

可以为返回ReturnType并且不将Delegate<ReturnType()>作为参数的函数实例化。我遇到了一个问题,要求我专门针对这种情况使用类()运算符,但是在没有编译器错误的情况下无法弄清楚如何强制编译器这样做。

我有以下功能:

template <typename R, typename... Args>
R Delegate<R(Args...)>::operator()(Args... args)
{ /*...*/ }

添加以下专业化,我收到一条错误invalid use of incomplete type 'class Delegate<R()>'

template <typename R>
R Delegate<R()>::operator()()
{ /*...*/ }

但我不能简单地将Args...替换为void,据我所知,这里的正确程序是什么,(如果这个问题适用,你感觉更有帮助吗?为什么?

1 个答案:

答案 0 :(得分:11)

由于§14.5.5.3[temp.class.spec.mfunc],您尝试使用R Delegate<R()>::operator()()专门化更多类模板的部分特化的成员函数失败:

  

1 类模板部分特化的成员的模板参数列表应与类模板部分特化的模板参数列表匹配。

换句话说:

template <typename R>
R Delegate<R()>::operator()() { /**/ }

实际上是主要模板 operator()的特化:

template <typename T>
class Delegate;

因为它是一个不完整的类型,你最终会得到错误。可能的解决方法是:

选项#1

专门化整个班级并重新实现该班级的所有成员:

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

选项#2

再使用一个专门的委托类:

#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

选项#3

使用一些丑陋的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

选项#4

从专门的类模板继承,可能使用 CRTP 成语:

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