Инициализация класса перечисления с помощью int - PullRequest
0 голосов
/ 06 июня 2018

Я обнаружил кое-что интересное при программировании:

enum class Foo {
  FOO_THING,
  FOO_TOO
};

int main() {
  Foo foo{1};    // It is OK
  Foo foo2(1);   // It is an invalid
}

Не могли бы вы сказать, почему foo{1} подходит для компилятора и почему foo2(1) недопустимо?

Компилятор GCC (g++ (Ubuntu 7.3.0-21ubuntu1~16.04) 7.3.0) говорит:

$ g++ -Wall -std=c++17 foo.cpp

  error: cannot convert ‘int’ to ‘Foo’ in initialization
  Foo foo2(1);

Я действительно хочу знать основную механику.:)))

Редактировать: Может быть, это какая-то ошибка компилятора ...

Ответы [ 2 ]

0 голосов
/ 06 июня 2018

Чтобы понять причины, по которым два синтаксиса не являются допустимыми, вы должны учитывать, что перечисления с областями видимости были введены со стандартом c ++ 11 для обеспечения статической проверки типов и имеют идентификаторы областей (т. Е. Больше не загрязняется имя).

Foo foo(1) не работает, поскольку неявное преобразование из целочисленного типа в перечисление с областью действия запрещено, в противном случае вы теряете преимущество перечислений с областью действия и избегаете конфликтов при разрешении перегрузки.

При использовании Foo foo{1} вы используете инициализацию списка , которая была также введена с c ++ 11, но получила обновление с c ++ 17, которое состоит в неявном преобразовании из значения int в enum, как сообщается здесь , если набор требований удовлетворен:

И типы перечисления с областью действия, и типы перечисления с незаданной областью, базовый тип которых фиксирован, могут быть инициализированы из целого числа без преобразования, используя инициализацию списка, если всеверно следующее:

  1. инициализация - прямая инициализация списка

  2. список инициализаторов содержит только один элемент

  3. перечисление либо ограничено, либо ограничено с фиксированным базовым типом

  4. преобразование не является узкимING.

Это позволяет вводить новые целочисленные типы (например, SafeInt), которые используют те же существующие соглашения о вызовах, что и их базовые целочисленные типы, даже на ABI, которые штрафуют передаваемые / возвращаемые структуры по значению.

Этот синтаксис является безопасным и не будет мешать устаревшему коду (написанному до c ++ 11), потому что в то время не существовало ни перечислений области действия, ни инициализации списка.Кроме того, как сообщается в цитате, это позволяет использовать новые целочисленные типы (например, типы из библиотеки SafeInt) без необходимости принудительного статического приведения типов перечислений в коде, который соответствует современному синтаксису c ++.

0 голосов
/ 06 июня 2018

C ++ 17-специфичная документация содержит следующее для фигурного инициализатора

В противном случае, если T является типом перечисления, который имеет область видимости или область с фиксированным базовым типом,и если в braced-init-list есть только один инициализатор, и если преобразование из инициализатора в базовый тип не является сужающим, и если инициализация является прямой инициализацией списка, то перечисление инициализируется с результатом преобразованияинициализатор к его базовому типу.

Так что foo, кажется, соответствует действительному C ++ 17, но foo2, не будучи инициализированным скобками, недопустим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...