Почему этот 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
Ответы
Ответ 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;
В объявлении допускается избыточная скобка.