函数调用参数中的构造函数样式转换

时间:2014-04-21 17:21:47

标签: c++ c++11 casting

我不明白为什么以下代码在使用构造函数样式的转换时无法编译:

template<typename T> void foo(const T& t){}

int main(){
  foo(unsigned char(0));
}

错误是:

  • error: expected primary-expression before ‘unsigned’ for gcc。
  • error: expected '(' for function-style cast or type construction for clang

然而,这三种语法是正确的:

template<typename T> void foo(const T& t){}

int main(){
  // c-style cast
  foo((unsigned char)0);

  // without unsigned
  foo(char(0));

  // aliased unsigned char
  typedef unsigned char uchar;
  foo(uchar(0));
}

所以这个类型的空间显然应该归咎于此。

我认为它可能与我们的老朋友the most vexing parse有某种关系,所以我尝试了uniform initialization syntax,这应该摆脱这种模棱两可,但没有运气:

template<typename T> void foo(const T& t){}

int main(){
  foo(unsigned char{0});
}

但仍然:

  • error: expected primary-expression before ‘unsigned’ for gcc。
  • error: expected '(' for function-style cast or type construction for clang

所以我的问题是为什么不允许在函数式转换中包含一个包含空格的类型?它看起来并不含糊。

note :我知道我可以写foo<unsigned char>(0),但它没有回答问题;)

1 个答案:

答案 0 :(得分:16)

  

[C++11: 5.2.3/1]: 简单类型说明符(7.1.6.2)或 typename-specifier (14.6),后跟带括号的表达式列表在给定表达式列表的情况下构造指定类型的值。 [..]

检查语法,我们发现从简单类型说明符生成中获取unsigned char的唯一方法是连接其中两个。

作为揭示表10相反的谣言的证据,我可能在不久前开始(:P),表格标题为“说明符”(注意可选的复数形式),并参考到下面的段落:

  

[C++11: 5.2.3/2]: [..] 表10总结了简单类型说明符的有效组合及其指定的类型。 (强调我的)

现在,在某些情况下允许组合 simple-type-specifiers

  

[C++11: 7.1.6.2/3]:当允许多个简单类型说明符时,它们可以按任何顺序与其他 decl-specifiers 自由混合。 [..]

...但是没有迹象表明这是功能符号的情况,它明确指出“ a 简单类型说明符” - 单数。

因此GCC是正确的,Visual Studio是错误的。

至于为什么就是这种情况......好吧,我不知道。我怀疑我们可能会提出一些模棱两可的边缘情况,但是Casey在下面的注释中提出了一个很好的观点,即允许这与函数调用语法不一致,因为函数的名称不能包含空格。