Enum битовое поле и агрегатная инициализация - PullRequest
0 голосов
/ 06 сентября 2018

Следующий код принят clang 6.0.0, но отклонен gcc 8.2

enum class E {
  Good, Bad,
};

struct S {
  E e : 2;
  int dummy;
};

S f() {
  return {E::Good, 100};
}

Пример живого крестника

GCC жалуется

ошибка: не удалось преобразовать '{Good, 100}' из '<brace-enclosed initializer list>' в 'S'

Какой из них правильный? Где в стандарте говорится об этой ситуации?

Ответы [ 2 ]

0 голосов
/ 08 сентября 2018

Это должно быть правильно, так что это ошибка gcc.

В конечном итоге мы получим инициализацию агрегата через [stmt.return] p2 , что говорит:

… Оператор return с фигурным списком инициализации инициализирует объект или ссылку, которые будут возвращены из функции путем копирования-инициализации списка ([dcl.init.list]) из указанного списка инициализатора. ...

затем [dcl.init.list] p3.2 говорит:

В противном случае, если T является агрегатом, выполняется инициализация агрегата ([dcl.init.aggr]). ...

В этот момент мы можем задаться вопросом, является ли это сужающим преобразованием и, следовательно, плохо сформированным, но [dcl.init.list] p7 не имеет каких-либо положений, охватывающих этот случай, и никаких других случаев в [ dcl.init.list] применить, чтобы сделать это плохо сформированным.

Мы можем видеть на аналогичном примере, который удаляет enum из уравнения, но сохраняет битовое поле, показывает, что ни gcc, ни clang не дают нам диагностику сужающего преобразования, что, как мы ожидаем, имеет место, хотя эта похожая проблема покрыта [dcl.init.list] p7.4 хотя и не плохо сформирован:

struct S2 {
    int e : 2 ;
    int dummy ;
} ;

S2 foo( int x ) {
   return {x, 100} ;
}

увидеть его в прямом эфире

Как видно, у gcc, похоже, нет проблем в других контекстах, т.е.

S f(E e1, int x) {  
  S s {e1,100} ;
  return s;
}

Итак, у вас есть обходные пути.

0 голосов
/ 06 сентября 2018

return {E::Good, 100}; выполняет копирование списка инициализации возвращаемого значения. Эффект этой инициализации списка - совокупная инициализация .

Так что же, S - это совокупность? Описание агрегата варьируется в зависимости от того, какую версию C ++ вы используете, но во всех случаях S должен быть агрегатом, поэтому его следует скомпилировать. Clang (и MSVC) ведут себя корректно.

Исправление очень простое. Измените оператор return, чтобы он возвращал правильно введенный объект:

return S{E::Good, 100};
...