【问题标题】:Constexpr pointer valueconstexpr 指针值
【发布时间】:2012-05-09 07:43:18
【问题描述】:

我正在尝试声明一个初始化为某个常量整数值的 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 接受所有这些。

【问题讨论】:

  • 这里为什么需要一个 constexpr?如果不使用函数, constexpr 是否与 const 实际上相同?
  • @RobertMason:嗯,例如,如果它是一个类的静态成员,而且它不是 constexpr,我就不能内联初始化它。
  • 也许静态内联成员函数比数据成员更合适。
  • @HighCommander4:你不允许内联初始化整数吗?指针在下面是整数(不是全部),所以即使它不完全是标准的(我不知道,我没有标准的副本)你应该能够让大多数编译器接受它.
  • @RobertMason:clang 和 gcc 不接受非 constexpr 指针的内联初始化。我不知道为什么——我也想知道原因。

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


【解决方案1】:

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

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

第一个项目符号排除了您的第一个示例。第二个例子被上面的第一个项目符号排除了,加上来自 [expr.cast]/4 的规则:

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

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

即使这些限制不适用于核心常量表达式,仍然无法使用通过转换整数产生的值来初始化 constexpr 指针,因为 constexpr 指针变量必须由 初始化地址常量表达式,通过[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 扩展。

【讨论】:

    【解决方案2】:

    原因是(一次,非常有帮助的)错误消息给出的原因:reinterpret_cast is not allowed in a constant expression。它被列为 5.19(第 2 段)中的显式例外之一。

    reinterpret_cast 更改为C 风格的演员表仍然会得到reinterpret_cast 的语义等价物,因此这无济于事(同样,消息非常明确)。

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

    【讨论】:

    • 他添加的应该是0xff/sizeof(*x)
    猜你喜欢
    • 1970-01-01
    • 2019-10-06
    • 2021-10-17
    • 2012-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多