c++ - Constexpr 指针值

标签 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 接受所有这些。

最佳答案

正如 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/

相关文章:

c++ - 预取大量引用数据的实际限制

c++ - 绘制的自定义项目有时会在 QGraphicsScene 中被砍掉

c++ - 为什么我必须在 C++ 中的 std::array<SomeStruct, size> 初始化时为每个项目指定类型

c - 指针所需的基本帮助(双重间接)

c - ASCII 字符未打印出来

c++ - 使用功能模板调用 C++ 类成员函数

c++ - 模板函数的奇怪输出的解释

c++ - void()、逗号运算符 (operator,) 和不可能的 (?) 重载

c - 将一个变量的地址分配给另一个变量

c++ - 使用 std::async() 和 std::move() 将数据异步传递给另一个线程