为什么使用带有默认构造函数的括号会导致创建变量?

Amo*_*mum 6 c++ most-vexing-parse language-lawyer

看完路易斯·布兰迪在CppCon 2017上的演讲后,我惊讶地发现这段代码实际编译:

#include <string>

int main() {

    std::string(foo);

    return 0;
}    
Run Code Online (Sandbox Code Playgroud)

由于某种原因,std::string(foo)它与std::string foo声明变量相同.我发现它绝对违反直觉,并且看不出C++以这种方式工作的任何理由.我希望这会给出一个关于未定义标识符的错误foo.

它实际上使表达式token1(token2)具有比我之前想象的更多可能的解释.

所以我的问题是:这种恐怖的原因是什么?这个规则什么时候真的有必要?

PS对不起措辞不好的标题,请随时更改!

Bar*_*rry 13

由于这个问题是标记,直接答案是,来自[stmt.ambig]:

在涉及表达式语句和声明的语法中存在歧义:具有函数式显式类型转换的表达式语句,因为其最左侧的子表达式与第一个声明符以a开头的声明无法区分(.在这些情况下,该声明是一个声明.

同样,对于函数,在[dcl.ambig.res]中:

函数式转换与[stmt.ambig]中提到的声明之间的相似性引起的歧义也可能出现在声明的上下文中.在该上下文中,选择在函数声明与参数名称周围的冗余括号集和具有函数样式转换作为初始化器的对象声明之间.正如[stmt.ambig]中提到的含糊不清一样,解决方案是考虑任何可能是声明声明的构造.

因此:

为什么哦为什么std::string("foo")这么不同呢std::string(foo)

前者不能是宣言.后者可以是一个声明,带有一组冗余的括号.因此,前者不是宣言而后者宣言.

根本的问题是,grammaticaly,声明符可以从一个开头,(这可能使它与函数式显式类型转换无法区分.语言只选择一个,而不是提出任意复杂的规则来尝试确定用户的意思,并且用户可以轻松修复代码以实际执行他的意思.