20

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

7
  • 2
    For what it's worth int main() { unsigned char c = unsigned char(0); } doesn't compile either using g++. Commented Apr 21, 2014 at 17:32
  • Please excuse my ignorance—but is not (unsigned char)(0) what the OP wants? Or does it have different semantics? (Simple yes/no answer is sufficient, I’ll dig into it deeper when you tell me it’s different by myself) Commented Apr 21, 2014 at 17:38
  • Also, both the constructs are successfully compiled by Visual Studio 2008. Commented Apr 21, 2014 at 17:38
  • @JonasWielicki Yours is a C-style casting. They are equivalent, but I was wondering if that was not a compiler bug, which would be bad. There are multiple semantically equivalent syntax, but I don't know why some are not valid. Commented Apr 21, 2014 at 17:40
  • 2
    I'm retracting my close vote; this is a duplicate of stackoverflow.com/questions/2963396/…, but that question doesn't look as good and the answers sort of skirt around the issue. I'm going to take the unusual step of voting that one as a dup of this one. Commented Apr 21, 2014 at 17:46

1 Answer 1

16

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

Sign up to request clarification or add additional context in comments.

15 Comments

@Thibaut VS2013 is compiling your code without any complaints. That's gotta be a first, where VS gets something right while clang and gcc don't. I think this answer is correct, because Table 10 under [dcl.type.simple] lists unsigned char as a simple-type-specifier.
@Thibaut: From the grammar, unsigned char looks more like multiple simple-type-specifiers "concatenated", which is at odds with Table 10.
Yeah, following on from my previous comment, I've changed my mind about what's going on here - GCC is right here. Table 10 is not at odds with anything if you read it properly ;)
Well, at least VS is back to being wrong. Everything's right with the world once more.
@Thibaut Grammatically, it makes sense. We can't have function names with spaces in them, so it's consistent to forbid multi-word function-style casts.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.