struct X
{
enum class E
{
A,B
};
static constexpr X A()
{
return X{E::A};
}
static constexpr X B()
{
return X{E::B};
}
constexpr operator E() const
{
return a;
}
E a;
};
template <typename T>
struct Y
{
void f()
{
// without this line clang errs
// const auto & x = this->x;
switch(x)
{
case X::A():
case X::B():
default: return;
}
}
X x = X::A();
};
int main()
{
Y<int>{}.f();
}
在片段clang中没有标记的行会出现以下错误:
错误:case值不是常量表达式case
X :: B():
但是我尝试了gcc,它编译良好。有人知道gcc是宽容还是c有一些错误?
参见Godbolt(t 8.0.0):https://godbolt.org/z/ETe5WQ 但是(gcc 8.3)可以很好地编译(也可以在Godbolt上使用),并尝试了其他版本的gcc,也很好
更新:
打开了一个bug
答案 0 :(得分:12)
C语(8.0.0)此处存在错误。
如果您在constexpr auto A = X::A();
语句中编写case A:
并使用switch
,则会出现相同的编译错误(表明A
不是一个常量表达式)。
但是,如果删除这些个案,它将编译良好(这意味着A
是有效的constexpr
=>与上一个错误的矛盾)。
此外,switch(x)
失败,而switch(this->x)
成功。由于在您的情况下,x == this->x
绝对是一个错误。
正如chtz所提到的,5(5/6)似乎工作正常。那不是争论,而是明显的回归。
更新:如OP所述,他们提交了bug report。
答案 1 :(得分:2)
似乎c语不能证明switch(x)
是枚举X::E
的开关。
如果您向X::E
(static_cast
或C风格或其他样式)添加显式强制转换,则代码无需更改即可编译。
这仅在您的班级是template
时发生。
使用switch(this->x)
也可以。
每当x
是该类的成员时,x
只是this->x
的另一个名称,即使在template
中,也必须是一个lang虫。 / p>
如何对非枚举/整数类型进行切换的规则很有趣,因为它们依赖于switch
表达式中任何枚举或整数类型的未指定强制转换运算符的存在,然后在case
表达式中调用相同的转换。