我试图声明一个初始化为某个常量整数值的 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
-- an operation that would have undefined behavior [Note: including [...] certain pointer arithmetic [...] -- end note]
第一个项目符号排除了您的第一个示例。第二个例子被上面的第一个项目符号加上来自 [expr.cast]/4 的规则排除:
The conversions performed by [...] a
reinterpret_cast
[...] can be performed using the cast notation of explicit type conversion. The same semantic restrictions and behaviors apply.
第二个项目符号由 WG21 core issue 1313 添加,阐明常量表达式中不允许对空指针进行指针运算。这排除了你的第三个例子。
即使这些限制不适用于核心常量表达式,仍然无法使用通过转换整数产生的值来初始化 constexpr
指针,因为必须初始化 constexpr 指针变量通过一个地址常量表达式,根据[expr.const]/3,它的计算结果必须为
the address of an object with static storage duration, the address of a function, or a null pointer value.
转换为指针类型的整数不是这些。
g++ 还没有严格执行这些规则,但它最近的版本已经越来越接近这些规则,所以我们应该假设它最终会完全执行它们。
如果您的目标是声明一个执行静态初始化的变量,您可以简单地删除 constexpr
—— clang 和 g++ 都会为此表达式发出一个静态初始化器。如果出于某种原因需要此表达式成为常量表达式的一部分,您有两种选择:
- 重组您的代码,以便传递 intptr_t 而不是指针,并在需要时(在常量表达式之外)将其转换为指针类型,或者
- 使用
__builtin_constant_p((int*)0xFF) ? (int*)0xFF : (int*)0xFF
。这种确切的表达式形式(在条件运算符的左侧带有__builtin_constant_p
)禁用条件运算符中的严格常量表达式检查,并且鲜为人知,但 documented , gcc 和 clang 都支持的非可移植 GNU 扩展。
关于c++ - Constexpr 指针值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47942242/