After watching Louis Brandy talk at CppCon 2017 I was shocked to discover that this code actually compiles:
#include <string>
int main() {
std::string(foo);
return 0;
}
And for some reason std::string(foo)
it is identical to std::string foo
i.e. declaring a variable. I find it absolutely counterintuitive and can't see any reason for C++ to work that way. I would expect this to give an error about undefined identifier foo
.
It actually makes expressions like token1(token2)
have even more possible interpretations than I previously thought.
So my question is: what is the reason for this horror? When is this rule actually necessary?
P.S. Sorry for the poorly worded title, please, feel free to change it!
Since this question is tagged language-lawyer, the direct answer is that, from [stmt.ambig]:
There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a
(
. In those cases the statement is a declaration.
And, similarly, for functions, in [dcl.ambig.res]:
The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in [stmt.ambig] can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in [stmt.ambig], the resolution is to consider any construct that could possibly be a declaration a declaration.
Hence:
Why oh why is
std::string("foo")
so different fromstd::string(foo)
The former cannot be a declaration. The latter can be a declaration, with a redundant set of parentheses. Thus, the former isn't a declaration and the latter is.
The underlying issue is that, grammaticaly, declarators can start with a (
which could make it indistinguishable from a function-style explicit type conversion. Rather than come up with arbitrary complex rules to try to determine what the user meant, the language just picks one, and it's easy enough for the user to fix the code to actually do what he meant.