我试图声明一个初始化为某个常量整数值的 constexpr 指针,但 clang 挫败了我的所有尝试:
尝试1:
constexpr int* x = reinterpret_cast<int*>(0xFF);
test.cpp:1:20: note: reinterpret_cast is not allowed in a constant expression
尝试2:
constexpr int* x = (int*)0xFF;
test.cpp:1:20: note: cast which performs the conversions of a reinterpret_cast is not allowed in a constant expression
尝试3:
constexpr int* x = (int*)0 + 0xFF;
test.cpp:1:28: note: cannot perform pointer arithmetic on null pointer
我试图做的事情是设计不允许的吗?如果是这样,为什么?如果没有,我该怎么办?
注意:gcc 接受所有这些。
正如 Luc Danton 所指出的,您的尝试会被 [expr.const]/2 中的规则阻止,这些规则规定核心常量表达式中不允许使用各种表达式,包括:
-- a reinterpret_cast
-- 具有未定义行为的操作 [注意:包括 [...] 某些指针算术 [...] -- 尾注]
第一个项目符号排除了您的第一个示例。第二个示例被上面的第一个项目符号排除,加上 [expr.cast]/4 中的规则:
由 [...] a 执行的转换reinterpret_cast
[...] 可以使用显式类型转换的强制转换表示法来执行。相同的语义限制和行为也适用。
第二个项目符号是由WG21 核心问题 1313,并澄清常量表达式中不允许对空指针进行指针算术。这排除了你的第三个例子。
即使这些限制不适用于核心常量表达式,仍然无法初始化constexpr
具有通过强制转换整数生成的值的指针,因为 constexpr 指针变量必须由地址常量表达式初始化,根据 [expr.const]/3,该变量必须计算为
具有静态存储持续时间的对象的地址、函数的地址或空指针值。
整数转换为指针类型都不是这些。
g++ 尚未严格执行这些规则,但其最近的版本已经越来越接近这些规则,因此我们应该假设它最终会完全实现这些规则。
如果您的目标是声明一个执行静态初始化的变量,您只需删除constexpr
-- clang 和 g++ 都会为此表达式发出静态初始值设定项。如果出于某种原因需要此表达式成为常量表达式的一部分,您有两种选择:
- 重构代码,以便传递 intptr_t 而不是指针,并在需要时将其转换为指针类型(在常量表达式之外),或者
- Use
__builtin_constant_p((int*)0xFF) ? (int*)0xFF : (int*)0xFF
。这种精确的表达形式(与__builtin_constant_p
在条件运算符的左侧)禁用条件运算符臂中的严格常量表达式检查,并且鲜为人知,但是记录在案,gcc 和 clang 支持的非可移植 GNU 扩展。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)