使用引用的constexpr静态成员作为模板参数

9

我正在尝试弄清楚GCC或Clang是否在这里有不同/错误地解释了C++17标准。

这是我的代码,使用GCC 8编译,但不能使用Clang 6编译:

struct BoolHolder {
    constexpr static bool b = true;
};

template<bool b>
class Foo {};

int main() {
    BoolHolder b;
    Foo<b.b> f; // Works

    BoolHolder & br = b;
    Foo<br.b> f2; // Doesn't work
}

我不明白为什么会这样。显然,b.b 是一个有效的 constexpr(否则第一个 Foo<b.b> 就无效了)。br.b 不是一个有效的 constexpr 吗?为什么?对象或引用本身与此无关,因为我们在这里访问的是静态 constexpr 成员,对吧?
如果这确实不是有效的 C++17 代码,那么即使我启用了 -Wall -Wextra -pedantic,GCC 也没有警告我,这是否应该被视为一个错误?

就此而言,MSVS和icc也可以编译。 - NathanOliver
我认为这与问题有关:对于constexpr int f(int) { return 0; },对于int xf(x)是否会成为constexpr?https://dev59.com/aafja4cB1Zd3GeqPuVl4 - Evg
我不会打赌说这个引用在这里是相关的。br不是constexpr,所以基于br的所有东西也不是constexpr。或许作为解决方法,你可以使用BoolHolder::b,如果BoolHolder在此上下文中不是常量,那么你可以使用decltype - Marcel
1个回答

10

Clang是正确的。 参考在常量表达式中被“急切地”评估,可以这么说。 根据抽象机器的规则评估e时,表达式e是核心常量表达式,除非其评估之一如下:

表达式e是核心常量表达式,除非根据抽象机器的规则评估e会评估以下表达式之一:

  • [...]
  • 引用类型的变量或数据成员的id-expression,除非该引用具有前置初始化,并且
    • 它用常量表达式进行了初始化,或者
    • 其生命周期始于对e的评估内;
  • [...]

谢谢,但是这里 …除非它被初始化为常量表达式… 部分应该是正确的吗?另外,表达式 br.b 真的应该评估为一个 id-expression 吗?这是静态成员访问,因此对象本身是无关紧要的。 - Lukas Barth
b 不是一个常量表达式。即使结果被丢弃,对象表达式仍然会被评估。 - T.C.
很遗憾它没有首先被解释为 BoolHolder::b - Jarod42
1
@Jarod42,如果x是静态数据成员,您是否希望f().x不对f()进行求值? - T.C.
“unless the reference has a preceding initialization” 是什么意思? - David G

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接