問題描述
我試圖聲明一個 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 指針值的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!