В чем разница между этими двумя версиями кода? - PullRequest
0 голосов
/ 21 февраля 2019

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

#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 ]

0 голосов
/ 21 февраля 2019

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

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

0 голосов
/ 21 февраля 2019

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

type(name)

. Из-за этого

B var(A(test)); 

объявляет функцию с именем var, которая возвращает B и принимает имя Atest

B var(A(20));

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

...