对[Args...]为空的可变模板进行部分模板特化。

问题描述 投票:4回答:1

我有一个班。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 或者,据我所知... ... 在这里,正确的程序是什么,(如果这个问题适用,你觉得特别有用的话)为什么?

c++ c++11 templates variadic-templates partial-specialization
1个回答
12
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.