C ++ 11:Variadic模板推导逻辑

时间:2017-09-05 07:24:59

标签: c++11 variadic-templates

我有以下结构:

template <class... Args>
class some_class
{
public:
    some_class() = default;
    some_class(Args...) = delete;
    ~some_class() = default;
};

template<>
class some_class<void>
{
public:
    some_class() = default;
    ~some_class() = default;
};

原因是我只想让用户使用默认构造函数创建对象,例如:

some_class<int,float> b;

应该可以工作但是

some_class<int,float> c(1,3.4);

应该给我一个编译错误。

在某些时候我还需要根据void创建模板,因此void的专业化:

some_class<void> a;

但是我错误地输入了:

some_class<> d;

突然我的代码停止编译,它给了我错误:

some_class<Args>::some_class(Args ...) [with Args = {}]’ cannot be 
overloaded
 some_class(Args...) = delete;

所以问题出现了:我觉得我错了,我认为some_class<>应该推导到void专业化......我只是不知道为什么。可以请某人解释为什么some_class<>(即:空参数列表)与some_class<void>不同? (标准中的几行会做:))

https://ideone.com/o6u0D6

1 个答案:

答案 0 :(得分:2)

void类似于任何其他类型(确切地说是不完整类型)。这意味着它通常可以用作类型模板参数的模板参数。使用您的类模板,这些都是完全有效的, distinct,实例化:

some_class<void>
some_class<void, void>
some_class<void, void, void>
some_class<void, char, void>

在第一种情况下,参数包Args有一个元素:void。在第二种情况下,它有两个元素:voidvoid。等等。

这与案例some_class<>完全不同,在这种情况下,参数包具有元素。您可以使用sizeof...

轻松演示此内容
template <class... Pack>
struct Sizer
{
  static constexpr size_t size = sizeof...(Pack);
};

int main()
{
  std::cout << Sizer<>::size << ' ' << Sizer<void>::size << ' ' << Sizer<void, void>::size << std::endl;
}

这将输出:

  

0 1 2

[Live example]

我无法真正想到引用标准的相关部分。也许这个(C ++ 11 [temp.variadic] 14.5.3 / 1):

  

模板参数包是一个模板参数,可接受零个或多个模板参数。 [示例:

template<class ... Types> struct Tuple { };
Tuple<> t0; // Types contains no arguments
Tuple<int> t1; // Types contains one argument: int
Tuple<int, float> t2; // Types contains two arguments: int and float
Tuple<0> error; // error: 0 is not a type
     

- 示例]