Constexpr pointer value(Constexpr 指针值)
问题描述
我试图声明一个 constexpr 指针初始化为某个常量整数值,但 clang 挫败了我的所有尝试:
I am trying to declare a constexpr pointer initialized to some constant integer value, but clang is foiling all my attempts:
尝试 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
设计不允许我尝试这样做吗?如果是这样,为什么?如果没有,我该怎么做?
Is what I'm trying to do not allowed by design? If so, why? If not, how can I do it?
注意:gcc 接受所有这些.
Note: gcc accepts all of these.
推荐答案
正如 Luc Danton 所指出的,您的尝试被 [expr.const]/2 中的规则阻止,其中规定 core 中不允许使用各种表达式常量表达式,包括:
As Luc Danton notes, your attempts are blocked by the rules in [expr.const]/2 which say that various expressions are not allowed in core constant expressions, including:
-- 一个 reinterpret_cast
-- 具有未定义行为的操作 [注意:包括 [...] 某些指针算法 [...] -- 尾注]
-- a
reinterpret_cast
-- an operation that would have undefined behavior [Note: including [...] certain pointer arithmetic [...] -- end note]
第一个项目符号排除了您的第一个示例.第二个例子被上面的第一个项目符号排除,加上来自 [expr.cast]/4 的规则:
The first bullet rules out your first example. The second example is ruled out by the first bullet above, plus the rule from [expr.cast]/4 that:
由 [...] a reinterpret_cast
[...] 执行的转换可以使用显式类型转换的强制转换表示法来执行.相同的语义限制和行为适用.
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 核心问题 1313 添加的,并阐明常量表达式中不允许对空指针进行指针运算.这排除了你的第三个例子.
The second bullet was added by WG21 core issue 1313, and clarifies that pointer arithmetic on a null pointer is not permitted in a constant expression. This rules out your third example.
即使这些限制不适用于核心常量表达式,仍然无法使用通过转换整数产生的值来初始化 constexpr
指针,因为必须初始化 constexpr 指针变量通过一个地址常量表达式,根据[expr.const]/3,它必须计算为
Even if these restrictions did not apply to core constant expressions, it would still not be possible to initialize a constexpr
pointer with a value produced by casting an integer, since a constexpr pointer variable must be initialized by an address constant expression, which, by [expr.const]/3, must evaluate to
具有静态存储期的对象地址、函数地址或空指针值.
the address of an object with static storage duration, the address of a function, or a null pointer value.
转换为指针类型的整数不是这些.
An integer cast to pointer type is none of these.
g++ 还没有严格执行这些规则,但它最近的版本已经越来越接近它们,所以我们应该假设它最终会完全实现它们.
g++ does not yet strictly enforce these rules, but its recent releases have been getting closer to them, so we should assume that it will eventually fully implement them.
如果您的目标是声明一个对其执行静态初始化的变量,您可以简单地删除 constexpr
——clang 和 g++ 都会为这个表达式发出一个静态初始化程序.如果出于某种原因需要将此表达式作为常量表达式的一部分,则有两种选择:
If your goal is to declare a variable for which static initialization is performed, you can simply drop the constexpr
-- both clang and g++ will emit a static initializer for this expression. If you need this expression to be part of a constant expression for some reason, you have two choices:
- 重构您的代码,以便传递 intptr_t 而不是指针,并在需要时将其转换为指针类型(常量表达式之外),或
- 使用
__builtin_constant_p((int*)0xFF) 吗?(int*)0xFF : (int*)0xFF
.这种确切的表达式形式(在条件运算符的左侧带有__builtin_constant_p
)禁用了条件运算符臂中的严格常量表达式检查,并且鲜为人知,但是 已记录,gcc 都支持的非便携式 GNU 扩展和叮当声.
- Restructure your code so that an intptr_t is passed around instead of a pointer, and cast it to pointer type when you need to (outside of a constant expression), or
- Use
__builtin_constant_p((int*)0xFF) ? (int*)0xFF : (int*)0xFF
. This exact form of expression (with__builtin_constant_p
on the left-hand-side of a conditional operator) disables strict constant expression checking in the arms of the conditional operator, and is a little-known, but documented, non-portable GNU extension supported by both gcc and clang.
这篇关于Constexpr 指针值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:Constexpr 指针值
基础教程推荐
- 如何使图像调整大小以在 Qt 中缩放? 2021-01-01
- Windows Media Foundation 录制音频 2021-01-01
- 管理共享内存应该分配多少内存?(助推) 2022-12-07
- 如何在不破坏 vtbl 的情况下做相当于 memset(this, ...) 的操作? 2022-01-01
- 在 C++ 中循环遍历所有 Lua 全局变量 2021-01-01
- 从 std::cin 读取密码 2021-01-01
- 如何“在 Finder 中显示"或“在资源管理器中显 2021-01-01
- 为什么语句不能出现在命名空间范围内? 2021-01-01
- 为 C/C++ 中的项目的 makefile 生成依赖项 2022-01-01
- 使用从字符串中提取的参数调用函数 2022-01-01