使用局部变量的引用来初始化 constexpr 变量是否有效?

phi*_*inz 7 c++ clang language-lawyer constexpr

以下代码只能在 GCC 上编译(在 godbolt.org 上检查了 10.4 和 13.2),但不能在 Clang 上编译(在我尝试过的所有版本上都失败,例如 godbolt.org 上的 17.0.1):

struct A {
  static constexpr int b{1};
};

int main(int argc, char *argv[]) { 
    A a;
    A& aref{a};
    constexpr auto bb1{a.b};
    constexpr auto bb2{aref.b};
    return bb1+bb2; 
}
Run Code Online (Sandbox Code Playgroud)

叮当输出:

struct A {
  static constexpr int b{1};
};

int main(int argc, char *argv[]) { 
    A a;
    A& aref{a};
    constexpr auto bb1{a.b};
    constexpr auto bb2{aref.b};
    return bb1+bb2; 
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/nG4j3KefE

为什么?

use*_*522 6

bb1总是被允许的。

bb2自P2280起就允许使用, P2280也被 C++23 接受为早期修订版的缺陷报告。

最初有一个特定的规则,在常量表达式中禁止使用在常量表达式中不可用引用变量(但仅限于引用变量!)(即用常量表达式初始化)或在常量表达式求值期间开始其生命周期。即使没有应用左值到右值转换并且没有其他任何东西依赖于特定的引用对象,这种情况也成立。这与非参考变量的使用不一致,缺陷报告修复了这个问题。你的例子说明了这种不一致。constexpr

从技术上讲,GCC 在缺陷报告之前并没有表现出一致,而 Clang 自报告以来也没有表现出一致,但可能只是还没有实现它。

  • @phinz 自 C++11 以来就一直存在,可能有点难以找到基本原理,但我认为当时 `constexpr` 的重点是允许非常简单的按值函数替换模板中的宏和算术元编程。我想没有重点关注通过引用使用对象,正如您在 P2280 中看到的那样,在放宽规则时仍然需要考虑一些细节。 (2认同)
  • @phinz作为对我的猜想的支持,他们只允许在“constexpr”上下文中引用 https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3078.html 相对较晚C++11 的起草。在此之前,仅允许值参数(无论如何,C++11 中都不允许 `constexpr` 函数中的变量声明)。 (2认同)

归档时间:

查看次数:

318 次

最近记录:

1 年,10 月 前