Constexpr指针值

时间:2012-04-29 04:07:48

标签: c++ pointers c++11 clang constexpr

我试图声明一个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接受所有这些。

2 个答案:

答案 0 :(得分:20)

正如Luc Danton所说,你的尝试被[expr.const] / 2中的规则所阻止,这些规则表明核心常量表达式中不允许使用各种表达式,包括:

  

- reinterpret_cast
   - 具有未定义行为的操作[注意:包括[...]某些指针算法[...] - 结束注释]

第一个子弹排除了你的第一个例子。第二个例子由上面的第一个子弹排除,加上[expr.cast] / 4的规则:

  

reinterpret_cast [...]执行的转换可以使用显式类型转换的强制转换表示法执行。适用相同的语义限制和行为。

第二个项目符号由WG21 core issue 1313添加,并阐明在常量表达式中不允许对空指针进行指针运算。这排除了你的第三个例子。

即使这些限制不适用于核心常量表达式,仍然无法使用通过转换整数生成的值初始化constexpr指针,因为constexpr指针变量必须由< i>地址常量表达式,通过[expr.const] / 3,必须求值为

  

具有静态存储持续时间的对象的地址,函数的地址或空指针值。

转换为指针类型的整数不是这些。

g ++还没有严格执行这些规则,但是它的最新版本已经越来越接近它们了,所以我们应该假设它最终会完全实现它们。

如果你的目标是声明一个执行静态初始化的变量,你可以简单地删除constexpr - clang和g ++都会为这个表达式发出一个静态初始化器。如果由于某种原因需要将此表达式作为常量表达式的一部分,则有两种选择:

  • 重构代码,以便传递intptr_t而不是指针,并在需要时(在常量表达式之外)将其强制转换为指针类型,或者
  • 使用__builtin_constant_p((int*)0xFF) ? (int*)0xFF : (int*)0xFF。这种精确的表达形式(在条件运算符的左侧有__builtin_constant_p)禁用条件运算符臂中的严格常量表达式检查,并且鲜为人知,但是documented ,gcc和clang支持的非便携式GNU扩展。

答案 1 :(得分:5)

原因是(一次,非常有用)错误消息给出的一个:reinterpret_cast在常量表达式中是不允许的。它被列为5.19(第2段)中的明确例外之一。

reinterpret_cast更改为C风格的强制转换仍然以语义等效于reinterpret_cast结束,因此无效(并且消息非常明确)。

如果你有办法获得一个值为0的指针,你确实可以使用p + 0xff,但我想不出一种方法来获得这样一个带有常量表达式的指针。您可以依赖于指针上下文中的空指针值(0,或者nullptr)在您的实现中具有值0,但是您已经看到了自己的实施拒绝这样做。我认为这样做是可以的。 (例如,允许实现大多数常量表达式。)