2017-09-05 58 views
2

我有以下结构:C++ 11:可变参数模板演绎逻辑

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

回答

2

void是像任何其他类型的(不完全的类型,要准确)。这意味着它通常可以用作类型模板参数的模板参数。以你的类模板,这些都是非常有效的,并且不同,实例:

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):

A template parameter pack is a template parameter that accepts zero or more template arguments. [ Example:

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 

—end example ]

+0

谢谢,你的回答完美地解释了情况...我原来的问题是有点高于这个水平,因为我使用参数包作为类的一些功能的参数类型(所以我自动将'void'翻译成不带参数的东西),我甚至有这种情况,当具体的值是从参数包中实例化,所以由于这种限制,我实际上从来没有想过把''放在那里,但实际上这个答案清楚地描述了情况。 – fritzone