Подтвердить что ты не робот

Почему этот enum не конвертируется в int?

Почему следующий код не компилируется под g++ (С++ 14), MSVC (С++ 14) или ARM (С++ 03)?

Именованный экземпляр Error вызывает конструктор integer, но анонимный экземпляр Error не разрешает.

class Error
{
public:
    Error(int err) : code_(err) {}
    const int code_;
};

enum Value
{
    value_1
};

int main()
{
    // compiles
    Error e(value_1);

    // does not compile under G++, ARM, or MSVC
    Error(value_1);
}

Пример ошибки в g++: (ссылка Coliru)

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out

main.cpp: In function 'int main()':
main.cpp:19:18: error: no matching function for call to 'Error::Error()'
     Error(value_1);
                  ^
main.cpp:4:5: note: candidate: Error::Error(int)
     Error(int err) : code_(err) {}
     ^~~~~
main.cpp:4:5: note:   candidate expects 1 argument, 0 provided
main.cpp:1:7: note: candidate: constexpr Error::Error(const Error&)
 class Error
       ^~~~~
main.cpp:1:7: note:   candidate expects 1 argument, 0 provided
main.cpp:1:7: note: candidate: constexpr Error::Error(Error&&)
main.cpp:1:7: note:   candidate expects 1 argument, 0 provided
4b9b3361

Ответ 1

Это происходит из того же места, что и "The Most Vexing Parse" - правило, которое, если оно может быть объявлением, является объявлением. И удивительно, что вам разрешено помещать круглые скобки вокруг идентификатора в объявлении переменной.
(Я понятия не имею, почему, но я предполагаю, что он упростил C-парсер в тот же день.)

Ниже перечислены все допустимые объявления переменных int:

int (foo);
int (bar) = 0;
int (baz)(3);
int (twaddle)(baz);

Ответ 2

Проблема в том, что код

Error(value_1);

представляет собой объявление переменной value_1 типа Error.

Это наследие языка C, которое использует выражения как часть объявления типа.

Например, int *i является указателем на int, потому что он говорит, что выражение *i должно оценивать тип int. Дополнительные примеры:

  • int (*func)() - это указатель на функцию return int, потому что выражение (*func)() оценивает тип int.
  • int *p[8] представляет собой массив указателей на int, потому что выражение *p[x] оценивает тип int.
  • int (*p)[8] является указателем на массив из 8 int (int[8]), потому что выражение (*p)[x] вычисляет тип int.

Аналогично int (i) является простой переменной типа int, поскольку выражение (i) вычисляет тип int.

Итак, поскольку С++ наследует это от C, он использует скобки как часть объявления типа, но также добавляет больше синтаксиса сверху, что приводит к неожиданным результатам.

В правиле, применяемом С++, говорится, что нужно обрабатывать все, что может быть объявлением как декларацией.


Подобная путаница, если ее часто вызывает такой код:

Error ec();

который является прямым объявлением функции ec, которая возвращает Error.

Ответ 3

main.cpp: 19: 18: ошибка: нет соответствующей функции для вызова "Ошибка:: Ошибка()"
    Ошибка (значение_1);

Компилятор пытается вызвать несуществующий конструктор по умолчанию Error::Error(), потому что видит

Error(value_1);

как объявление переменной

Error  value_1;

В объявлении допускается избыточная скобка.