c++ - [Args...] 为空的可变参数模板的部分模板特化

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

我有课,Delegate , 声明如下:

template<typename T> class Delegate;

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

它可以被实例化为一个返回 ReturnType 的函数并且不接受参数作为 Delegate<ReturnType()> .我遇到了一个问题,需要我专门研究类(class)' ()这种情况下的运算符,但一直无法弄清楚如何在没有编译器错误的情况下强制编译器这样做。

我有以下功能:

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或者,据我所知...这里的正确程序是什么,以及(如果这个问题适用并且您感觉特别有帮助)为什么?

最佳答案

您尝试使用 R Delegate<R()>::operator()()特化甚至更多类模板的部分特化的成员函数由于§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.

换句话说:

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

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

#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

关于c++ - [Args...] 为空的可变参数模板的部分模板特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26987216/

相关文章:

c++ - 子类构造器

c++ - 有没有办法在非模板类中定义模板成员? #2

c++ - 静态常量类成员的多重定义错误

c++ - 如何在 C++ 控制台中删除一个已经写入的字符

c++ - 寻找堆栈损坏错误的解释

c++ - 有没有办法向原始类型添​​加转换运算符?

c++ - Qt 中的智能指针内存管理器

javascript - mustache 模式下划线模板中的循环

c++ - 二进制 '[' : no operator found which takes a left-hand operand of type 'const std::map<_Kty,_Ty>'

c++ - boost::asio 与标准 C socket 接口(interface)的配合