В чем разница между этими двумя версиями кода?

Этот код вызывает ошибку компиляции (самый неприятный анализ)

#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 вместо 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;
}

Почему это не считается самым неприятным разбором? В чем разница между этими двумя версиями кода?

2 ответа

Решение

Переменная может быть определена как

type(name)

Из-за этого

B var(A(test)); 

объявляет функцию с именем var который возвращает B и берет A названный test, В

B var(A(20));

если вы пытались сделать то же самое, A параметр будет называться 20, который не является допустимым именем переменной. Поскольку это не может быть именем переменной, мы знаем, что это значение, и вместо этого мы создаем переменную с именем var типа B со значением A(20),

Наиболее неприятный вопрос - проблема грамматики, а не семантики. Грамматически, A(test) сводится к identifier : OPEN_PAREN : identifier : CLOSE_PAREN, В контексте это неоднозначно, потому что вторым идентификатором может быть имя переменной или имя типа. Компилятор должен выбрать способ интерпретации этой последовательности токенов, и ни один из них не является неправильным.

В отличие от A(20) сводится к identifier : OPEN_PAREN : integer_literal : CLOSE_PAREN, Целочисленный литерал нельзя интерпретировать как идентификатор, поэтому нет способа интерпретировать его как имя типа. Поэтому он должен быть проанализирован как выражение, которое инициализирует объект типа A,

Другие вопросы по тегам