【问题标题】:What is the difference between these two versions of code?这两个版本的代码有什么区别?
【发布时间】:2019-07-15 14:21:02
【问题描述】:

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

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

但是如果我通过20而不是testA(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;
}

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

【问题讨论】:

  • 这基本上就是on Wikipedia的例子。第二种情况并不麻烦,因为20 不能是变量名。

标签: c++ c++11 most-vexing-parse


【解决方案1】:

变量可以这样定义

type(name)

因为这个

B var(A(test)); 

声明一个名为var 的函数,它返回一个B 并接受一个名为testA。在

B var(A(20));

如果您尝试做同样的事情,A 参数将被称为20,这不是一个有效的变量名。由于它不能是变量的名称,我们知道它是一个值,因此我们正在构造一个名为 var 的变量,其类型为 B,其值为 A(20)

【讨论】:

    【解决方案2】:

    最令人头疼的解析问题是语法问题,而不是语义问题。从语法上讲,A(test) 归结为identifier : OPEN_PAREN : identifier : CLOSE_PAREN。在上下文中,这是模棱两可的,因为第二个标识符可能是变量名或类型名。编译器必须选择一种方式来解释这个标记序列,并且没有一个是不正确的。

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

    【讨论】:

      猜你喜欢
      • 2020-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-06
      • 2020-03-29
      • 2018-04-16
      相关资源
      最近更新 更多