函数调用参数中的构造函数类型转换

2021-12-31 00:00:00 casting c++ c++11

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

I don't understand why the following code fails to compile when using constructor-style casting:

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

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

错误是:

  • 错误:gcc 的无符号"之前的预期主表达式.
  • 错误:函数式转换或类型构造的预期'(' for clang
  • error: expected primary-expression before ‘unsigned’ for gcc.
  • error: expected '(' for function-style cast or type construction for clang

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

However these three syntaxes are correct:

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));
}

所以类型中的空间显然是这里的罪魁祸首.

So the space in the type is obviously to blame here.

我认为这可能与我们的老朋友最烦人的解析有关,所以我尝试了统一初始化语法,应该可以消除这种歧义,但没有运气:

I thought it might be somehow related to our old friend the most vexing parse, so I tried the uniform initialization syntax, which is supposed to get rid of this sort of ambiguities, but no luck:

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

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

但仍然:

  • 错误:gcc 的无符号"之前的预期主表达式.
  • 错误:函数式转换或类型构造的预期'(' for clang
  • error: expected primary-expression before ‘unsigned’ for gcc.
  • error: expected '(' for function-style cast or type construction for clang

所以我的问题是为什么不允许在函数样式转换中包含包含空格的类型?对我来说,这看起来并不模棱两可.

So my question is why is it not allowed to have a type containing a space in function-style casts? It doesn't look ambiguous to me.

注意:我知道我可以写foo(0),但它没有回答问题;)

note: I know I can write foo<unsigned char>(0), but it doesn't answer the question ;)

推荐答案

[C++11: 5.2.3/1]: 简单类型说明符 (7.1.6.2) 或 类型名称说明符em> (14.6) 后跟带括号的 expression-list 构造给定表达式列表的指定类型的值.[..]

[C++11: 5.2.3/1]: A simple-type-specifier (7.1.6.2) or typename-specifier (14.6) followed by a parenthesized expression-list constructs a value of the specified type given the expression list. [..]

检查语法,我们发现从 simple-type-specifier 产生式中获取 unsigned char 的唯一方法是连接它们中的两个.

Examining the grammar, we see that the only way to get unsigned char from the simple-type-specifier production is by concatenating two of them.

作为揭穿表 10 陈述相反的谣言的证据,我可能自己不久前就开始了 (:P),表格标题写着说明符(s)"(注意可选的复数),并参考到下面的段落:

As evidence debunking the rumour that table 10 is stating the contrary, which I may myself have started a short while ago (:P), the table heading says "specifier(s)" (note the optional plural), and refer to the below passage:

[C++11: 5.2.3/2]: [..] 表 10 总结了 的有效组合>simple-type-specifiers 和它们指定的类型.(强调我的)

[C++11: 5.2.3/2]: [..] Table 10 summarizes the valid combinations of simple-type-specifiers and the types they specify. (emphasis mine)

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

Now, combining simple-type-specifiers is allowed in some cases:

[C++11: 7.1.6.2/3]: 当允许多个 simple-type-specifiers 时,它们可以与其他 自由混合声明说明符 以任何顺序.[..]

[C++11: 7.1.6.2/3]: When multiple simple-type-specifiers are allowed, they can be freely intermixed with other decl-specifiers in any order. [..]

…但没有迹象表明这是功能符号的情况,它清楚地指出a simple-type-specifier" —单数.

… but there's no indication that this is the case with functional notation, which clearly states "a simple-type-specifier" — singular.

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

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

As for why this is the case... well, I don't know. I suspect we could come up with some ambiguous edge case, but Casey makes a good point in the comments below that allowing this would be inconsistent with function call syntax, since names of functions cannot have spaces in them.

相关文章