以下代码被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};
}
海湾合作委员会抱怨
错误:无法将“
{Good, 100}
”从“<brace-enclosed initializer list>
”转换为“S
”
哪个是正确的?标准在哪里谈论这种情况?
答案 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])初始化要从函数返回的对象或引用。 …
否则,如果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} ;
}
如所观察到的,在其他情况下,即gcc似乎没有问题。
S f(E e1, int x) {
S s {e1,100} ;
return s;
}
所以您确实有变通办法。