这两个版本的代码有什么区别?

bor*_*ree 5 c++ most-vexing-parse c++11

此代码导致编译错误(最令人烦恼的解析)

#include <iostream>

class A {
        int a;
public:
        A(int x) :a(x) {}
};

class B {
public:
        B(const A& obj) { std::cout << "B\n";}
        void foo() {std::cout << "foo\n";}
};

int main()
{
        int test = 20;
        B var(A(test));      //most vexing parse
        var.foo();
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是如果我传递20而不是test(A(20)而不是A(test)),则没有编译错误.

#include <iostream>

class A {
        int a;
public:
        A(int x) :a(x) {}
};

class B {
public:
        B(const A& obj) { std::cout << "B\n";}
        void foo() {std::cout << "foo\n";}
};

int main()
{
        int test = 20;
        //B var(A(test));
        B var(A(20));            //ok works fine
        var.foo();
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

为什么这不被认为是最令人烦恼的解析?这两个代码版本有什么区别?

Nat*_*ica 10

变量可以定义为

type(name)
Run Code Online (Sandbox Code Playgroud)

因此

B var(A(test)); 
Run Code Online (Sandbox Code Playgroud)

声明了一个名为函数var返回一个B,并采取了A命名test.在

B var(A(20));
Run Code Online (Sandbox Code Playgroud)

如果您尝试执行相同的操作,A将调用该参数,该参数20不是有效的变量名称.因为它不能是变量的名称,我们知道它是一个值,而是我们构造一个名为vartype 的变量B,其值为A(20).


Nic*_*las 5

最令人烦恼的解析问题是语法问题,而不是语义问题.在语法上,A(test)归结为identifier : OPEN_PAREN : identifier : CLOSE_PAREN.在上下文中,这是不明确的,因为第二个标识符可以是变量名或类型名.编译器必须选择一种解释这个令牌序列的方法,而且两者都不正确.

相比之下,A(20)归结为identifier : OPEN_PAREN : integer_literal : CLOSE_PAREN.整数文字不能解释为标识符,因此无法将其解释为类型名称.因此必须将其解析为初始化类型对象的表达式A.