Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructor-style casting in function call parameters

Tags:

c++

casting

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

The errors are:

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

But still:

  • 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.

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

like image 844
Thibaut Avatar asked Apr 21 '14 17:04

Thibaut


1 Answers

[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. [..]

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.

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]: [..] Table 10 summarizes the valid combinations of simple-type-specifiers and the types they specify. (emphasis mine)

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

[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. [..]

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

Therefore GCC is correct, and Visual Studio is wrong.

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.

like image 195
Lightness Races in Orbit Avatar answered Oct 31 '22 12:10

Lightness Races in Orbit