具有可变模板参数的临时对象;另一个 g++/clang++ 区别
temporary objects with variadic template arguments; another g++/clang++ difference
如下代码
struct foo
{
foo ()
{ }
template <typename T0, typename ... Ts>
foo (const T0 & t0, const Ts & ... ts)
{ foo(ts...); }
};
int main()
{
foo f(1, 2);
return 0;
}
使用 g++
(4.9.2) 编译没有问题并给出以下错误
tmp_002-11,14,gcc,clang.cpp:9:16: error: expected ')'
{ foo(ts...); }
^
tmp_002-11,14,gcc,clang.cpp:9:13: note: to match this '('
{ foo(ts...); }
^
tmp_002-11,14,gcc,clang.cpp:9:14: error: redefinition of 'ts'
{ foo(ts...); }
^
tmp_002-11,14,gcc,clang.cpp:8:42: note: previous definition is here
foo (const T0 & t0, const Ts & ... ts)
^
2 errors generated.
与 clang++
(3.5)。
像往常一样,我的问题是:谁是对的?
--- 编辑 ---
澄清:我知道 foo(ts...)
不能调用委托构造函数,但(我认为可以)构造临时 foo
对象(另一个 foo
对象)。
但是,正如 vsoftco 所指出的,sizeof...(ts) == 1U
时发生了什么?
在那种情况下,foo(ts...);
是单个变量 ts
的(重新)声明(所以,我想,应该是正确的 clang++
)或者可变语法避免这种情况问题(所以,我想,应该是对的g++
)?
是否有 C++11 标准专家可以阐明这一点?
p.s.: 抱歉我的英语不好
这看起来像是一个 clang 错误。这是一个最小的复制:
template <typename ... Ts> void foo (Ts ... ts)
{
int(ts...);
}
(甚至不需要实例化模板)。
从错误消息来看,clang 将 int(ts...);
解释为声明,但它不能是,因为 (ts...)
不能是声明符。
有人可能会问:当 ts... 是一个大小为 1 的参数包时,它不应该像 ts
那样被解析,从而导致整个构造被解释为一个声明吗?答案是否定的。
"declaration" 和 "expression-statement" 产生式之间的 C++ 文法中存在语法歧义。如果一个有歧义的结构可以被解析为 "declaration",那么它就是 "declaration"。 int(ts...)
不能这样解析,因为文法没有这样解析所需的产生式。一旦构造被归类为表达式语句,而不是在此之前,我们可以将 ts...
解释为参数包并计算 sizeof...(ts)。如果该构造不属于表达式,则 sizeof...(ts) 根本没有意义,因为 ts... 没有意义,因为这样的语法不能在声明中。
一旦确定int(ts...);
是表达式语句而不是声明,就可以对其进行解释并实例化相关模板和扩展参数包。在这一点上,基于 sizeof...(ts) == 1
的事实,回过头来声称它一直是一个声明已经太晚了。不可能推断出 sizeof...(ts) == 1
如果它是一个声明(那么 ts
就不会是一个参数包)。
此外,clang 似乎暗示它甚至不是语法正确的声明。人们不可能从句法不正确的东西中推导出像 sizeof...(ts) == 1
这样的事实。
如下代码
struct foo
{
foo ()
{ }
template <typename T0, typename ... Ts>
foo (const T0 & t0, const Ts & ... ts)
{ foo(ts...); }
};
int main()
{
foo f(1, 2);
return 0;
}
使用 g++
(4.9.2) 编译没有问题并给出以下错误
tmp_002-11,14,gcc,clang.cpp:9:16: error: expected ')'
{ foo(ts...); }
^
tmp_002-11,14,gcc,clang.cpp:9:13: note: to match this '('
{ foo(ts...); }
^
tmp_002-11,14,gcc,clang.cpp:9:14: error: redefinition of 'ts'
{ foo(ts...); }
^
tmp_002-11,14,gcc,clang.cpp:8:42: note: previous definition is here
foo (const T0 & t0, const Ts & ... ts)
^
2 errors generated.
与 clang++
(3.5)。
像往常一样,我的问题是:谁是对的?
--- 编辑 ---
澄清:我知道 foo(ts...)
不能调用委托构造函数,但(我认为可以)构造临时 foo
对象(另一个 foo
对象)。
但是,正如 vsoftco 所指出的,sizeof...(ts) == 1U
时发生了什么?
在那种情况下,foo(ts...);
是单个变量 ts
的(重新)声明(所以,我想,应该是正确的 clang++
)或者可变语法避免这种情况问题(所以,我想,应该是对的g++
)?
是否有 C++11 标准专家可以阐明这一点?
p.s.: 抱歉我的英语不好
这看起来像是一个 clang 错误。这是一个最小的复制:
template <typename ... Ts> void foo (Ts ... ts)
{
int(ts...);
}
(甚至不需要实例化模板)。
从错误消息来看,clang 将 int(ts...);
解释为声明,但它不能是,因为 (ts...)
不能是声明符。
有人可能会问:当 ts... 是一个大小为 1 的参数包时,它不应该像 ts
那样被解析,从而导致整个构造被解释为一个声明吗?答案是否定的。
"declaration" 和 "expression-statement" 产生式之间的 C++ 文法中存在语法歧义。如果一个有歧义的结构可以被解析为 "declaration",那么它就是 "declaration"。 int(ts...)
不能这样解析,因为文法没有这样解析所需的产生式。一旦构造被归类为表达式语句,而不是在此之前,我们可以将 ts...
解释为参数包并计算 sizeof...(ts)。如果该构造不属于表达式,则 sizeof...(ts) 根本没有意义,因为 ts... 没有意义,因为这样的语法不能在声明中。
一旦确定int(ts...);
是表达式语句而不是声明,就可以对其进行解释并实例化相关模板和扩展参数包。在这一点上,基于 sizeof...(ts) == 1
的事实,回过头来声称它一直是一个声明已经太晚了。不可能推断出 sizeof...(ts) == 1
如果它是一个声明(那么 ts
就不会是一个参数包)。
此外,clang 似乎暗示它甚至不是语法正确的声明。人们不可能从句法不正确的东西中推导出像 sizeof...(ts) == 1
这样的事实。