使用局部变量引用初始化constexpr变量是否合法?GCC与Clang编译差异解析
用局部变量的引用初始化constexpr变量是否合法?
以下代码能在GCC 10.4、13.2版本编译通过,但所有版本的Clang(如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}; |
编译器差异原因
这段代码的合法性争议,源于不同编译器对C++标准中常量表达式规则的细节解读不同:
A::b是类的静态constexpr成员,本身是合法的常量表达式,无论通过对象实例还是类名访问,本质都是直接引用这个静态成员的值。- 对于
bb1,所有编译器都认可a.b等价于A::b,因此可以作为constexpr变量的初始化值。 - 争议焦点在
bb2:通过局部引用aref访问b。- Clang的逻辑是:
aref是绑定到局部变量的引用,本身不是常量表达式,因此以它为前缀的成员访问表达式也不能作为常量表达式。 - GCC的逻辑是:访问静态成员时,不需要依赖引用绑定的具体对象(静态成员属于类而非对象实例),
aref.b会被直接解析为A::b,因此属于合法的常量表达式。
- Clang的逻辑是:
从C++标准的设计意图来看,静态成员的访问不依赖于对象身份,GCC的处理更贴合这一逻辑;而Clang的实现则对常量表达式的构成做了更严格的校验。
内容的提问来源于stack exchange,提问作者phinz
相关产品推荐
相关产品推荐

