提问人:phinz 提问时间:10/31/2023 最后编辑:phinz 更新时间:11/4/2023 访问量:305
使用对局部变量的引用来初始化 constexpr 变量是否有效?
Is it valid to use a reference to a local variable to initialize a constexpr variable?
问:
以下代码仅在 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;
}
Clang 输出:
<source>:9:20: error: constexpr variable 'bb2' must be initialized by a constant expression
9 | constexpr auto bb2{aref.b};
| ^ ~~~~~~~~
<source>:9:24: note: initializer of 'aref' is not a constant expression
9 | constexpr auto bb2{aref.b};
| ^
<source>:7:14: note: declared here
7 | A& aref{a};
|
https://godbolt.org/z/nG4j3KefE
为什么?
答:
我觉得这是一个与这个问题和这个问题相似的“物种”问题。最后一个答案(这个问题)有一个评论,即 gcc 无法识别错误,这是贯穿上述答案的主题。 你的问题的答案可能只是一个平淡无奇的“clang比gcc更接近C++标准”。我相信每个人都知道编写编译器绝非易事,有些语法只是逃脱了 tokeniser/开发团队等。再加上完成软件的下行压力,GCC 团队无法涵盖当前 C++ 标准以及 LLVM 团队的所有方面。
引用这篇文章(接近结尾):“Clang 和 LLVM 比 GCC 更严格地遵守 C 和 C++ 标准。在 GCC 升级期间不会发生 GNU 内联和其他问题。
如果:
struct A {
static constexpr int b{1};
};
A a; // a is now global
int main(int argc, char *argv[]) {
// A a;
A& aref{a};
constexpr auto bb1{a.b};
constexpr auto bb2{aref.b};
return bb1+bb2;
}
(如果)A a 是全局的,即在 main() 之前声明,所有编译器都会编译,因为引用不会是本地对象,因此可以是 const(对于 constexpr)。对本地对象的引用(即使在 main() 中)也不被视为 const。
评论
bb1
总是被允许的。
bb2
自 P2280 以来是允许的,P2280 也被 C++23 接受为早期修订版的缺陷报告。
最初有一个特定的规则,即在常量表达式中禁止使用任何在常量表达式中不可用的引用变量(但只能使用引用变量!)(即 使用常量表达式初始化)或在常量表达式计算期间开始其生存期。即使没有应用左值到右值的转换,并且没有其他任何内容依赖于特定的引用对象,这也成立。这与非参考变量的使用不一致,缺陷报告修复了这个问题。您的示例演示了不一致之处。constexpr
从技术上讲,GCC 在缺陷报告之前没有表现出符合性,而 Clang 在缺陷报告之后也没有表现出符合性,但可能只是还没有实现它。
评论
constexpr
constexpr
constexpr
评论
A::b
.