这是使用sizeof ...()运算符的错误吗?

Abe*_*der 2 c++ compiler-construction sizeof variadic-templates

我遇到了来自clang ++编译器的sizeof ...()运算符的奇怪行为:

template <typename... Args>
void test(tuple<Args...> t) {
    cout << "size: " << sizeof...(Args) << endl;
}

...
test(make_tuple(1, 2)); // prints 'size: 10'
Run Code Online (Sandbox Code Playgroud)

我意识到更标准的方法是:

template <typename... Args>
void test(tuple<Args...> t) {
   cout << "size: " << tuple_size<tuple<Args...> >::value << endl;
}

test(make_tuple(1, 2)); // prints 'size: 2'
Run Code Online (Sandbox Code Playgroud)

但我仍然很好奇为什么我得到第一个版本的奇怪值.对于这种情况,sizeof ...()的值是不定义的,还是编译器行为不端?

R. *_*des 9

这听起来很像旧的可变参数模板仿真和真正的可变参数模板之间的不匹配.

在变参数模板出现之前,人们可以使用有限数量的默认模板参数来模拟它们:

struct void_ {}; // marker type not used anywhere else

template <typename T0 = void_,
          typename T1 = void_,
          typename T2 = void_,
          typename T3 = void_,
          typename T4 = void_,
          typename T5 = void_,
          typename T6 = void_,
          typename T7 = void_,
          typename T8 = void_,
          typename T9 = void_>
struct tuple { /* blah blah magic here */ };
Run Code Online (Sandbox Code Playgroud)

这允许人们写入tuple<int>,tuple<int, double>等等,最多十个参数.

tuple_size然后可以通过在第一个之前计算模板参数的数量来实现void_.功能集的其余部分以类似的方式实现.

可悲的是,这个技巧与真正的可变参数模板相互作用很差.给定时tuple<int, double>,类型推导tuple<Args...>将推导出Args包为{int,double,void_,void_,void_,void_,void_,void_,void_,void_}.这就是为什么sizeof...(Args)返回10:该包中确实有十种类型,即使其中八种只是我们决定赋予"无类型看这里,移动"的含义的标记.

编译器不知道我们的约定,所以它计算一切.tuple_size知道这个约定,只计算我们关心的实际类型.