枚举位域和聚合初始化

时间:2018-09-05 23:11:13

标签: c++ c++11 language-lawyer bit-fields enum-class

以下代码被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};
}

Live godbolt example

海湾合作委员会抱怨

  

错误:无法将“ {Good, 100}”从“ <brace-enclosed initializer list>”转换为“ S

哪个是正确的?标准在哪里谈论这种情况?

2 个答案:

答案 0 :(得分:4)

return {E::Good, 100};执行copy list initialization的返回值。此列表初始化的结果是aggregate initialization

S是一个聚合吗? aggregate的描述因您使用的C ++版本而异,但是在所有情况下,S应该是聚合的,因此应该进行编译。 Clang(和MSVC)具有正确的行为。

但是,修复很简单。更改您的return语句以返回正确键入的对象:

return S{E::Good, 100};

答案 1 :(得分:3)

这应该格式正确,所以这是一个gcc错误。

我们最终通过[stmt.return]p2进行了聚合初始化,它表示:

  

…带有括号初始化列表的return语句通过从指定的初始化程序列表进行复制列表初始化([dcl.init.list])初始化要从函数返回的对象或引用。 …

然后[dcl.init.list]p3.2说:

  

否则,如果T为聚合,则执行聚合初始化([dcl.init.aggr])。 …

在这一点上,我们可能想知道这是否是缩小的转换,因此格式不正确,但是[dcl.init.list]p7没有任何涵盖此情况的子句,并且[dcl.init.list]中的其他情况均不适用这个格式不正确。

我们可以看到一个类似的示例,该示例从等式中删除了枚举,但保持位字段显示gcc或clang都没有给我们提供缩小的转换诊断,尽管这种相似的问题已由{ {3}},尽管格式不正确:

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

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

[dcl.init.list]p7.4

如所观察到的,在其他情况下,即gcc似乎没有问题。

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

所以您确实有变通办法。