枚举位域和聚合初始化
Enum bitfield and aggregate initialization
以下代码被 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 抱怨
error: could not convert '{Good, 100}
' from '<brace-enclosed initializer list>
' to 'S
'
哪一个是正确的?标准中哪里谈到了这种情况?
return {E::Good, 100};
执行 copy list initialization of the return value. The effect of this list initialization is an aggregate initialization.
那么S
是聚合吗? aggregate 的描述因您使用的 C++ 版本而异,但在所有情况下 S
应该是一个聚合,因此应该可以编译。 Clang(和 MSVC)具有正确的行为。
虽然修复很简单。将您的 return 语句更改为 return 正确键入的对象:
return S{E::Good, 100};
这应该是格式正确的,所以这是一个 gcc 错误。
我们最终通过 [stmt.return]p2 进行聚合初始化,其中表示:
… A return statement with a braced-init-list initializes the object or reference to be returned from the function by copy-list-initialization ([dcl.init.list]) from the specified initializer list. …
然后 [dcl.init.list]p3.2 说:
Otherwise, if T is an aggregate, aggregate initialization is performed ([dcl.init.aggr]). …
在这一点上,我们可能想知道这是否是一个缩小转换,因此格式错误,但 [dcl.init.list]p7 没有任何条款涵盖这种情况,[dcl.init.list] 中的其他情况也不适用使这个格式错误。
我们可以看到一个类似的例子,它从等式中删除了枚举,但保留了位域显示,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;
}
所以您确实有可用的解决方法。
以下代码被 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 抱怨
error: could not convert '
{Good, 100}
' from '<brace-enclosed initializer list>
' to 'S
'
哪一个是正确的?标准中哪里谈到了这种情况?
return {E::Good, 100};
执行 copy list initialization of the return value. The effect of this list initialization is an aggregate initialization.
那么S
是聚合吗? aggregate 的描述因您使用的 C++ 版本而异,但在所有情况下 S
应该是一个聚合,因此应该可以编译。 Clang(和 MSVC)具有正确的行为。
虽然修复很简单。将您的 return 语句更改为 return 正确键入的对象:
return S{E::Good, 100};
这应该是格式正确的,所以这是一个 gcc 错误。
我们最终通过 [stmt.return]p2 进行聚合初始化,其中表示:
… A return statement with a braced-init-list initializes the object or reference to be returned from the function by copy-list-initialization ([dcl.init.list]) from the specified initializer list. …
然后 [dcl.init.list]p3.2 说:
Otherwise, if T is an aggregate, aggregate initialization is performed ([dcl.init.aggr]). …
在这一点上,我们可能想知道这是否是一个缩小转换,因此格式错误,但 [dcl.init.list]p7 没有任何条款涵盖这种情况,[dcl.init.list] 中的其他情况也不适用使这个格式错误。
我们可以看到一个类似的例子,它从等式中删除了枚举,但保留了位域显示,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;
}
所以您确实有可用的解决方法。