![](/img/trans.png)
[英]Why has std::accumulate not been made constexpr in C++20?
[英]Why isn't std::swap marked constexpr before C++20?
在 C++20 中, std::swap
變成了constexpr
函數。
我知道標准庫在標記事物constexpr
方面確實落后於語言,但到 2017 年, <algorithm>
和其他一些東西一樣,幾乎都是 constexpr。 然而 - std::swap
不是。 我依稀記得有一些奇怪的語言缺陷阻止了那個標記,但我忘記了細節。
有人可以簡潔明了地解釋這一點嗎?
動機:需要理解為什么在 C++11/C++14 代碼中標記一個std::swap()
的函數constexpr
可能是個壞主意。
奇怪的語言問題是CWG 1581 :
第 15 條 [特殊] 非常清楚,特殊成員函數僅在 odr 使用時才隱式定義。 這給未計算上下文中的常量表達式帶來了問題:
struct duration { constexpr duration() {} constexpr operator int() const { return 0; } }; // duration d = duration(); // #1 int n = sizeof(short{duration(duration())});
這里的問題是我們不允許在這個程序中隱式定義
constexpr duration::duration(duration&&)
,所以初始化列表中的表達式不是一個常量表達式(因為它調用了一個尚未定義的 constexpr 函數),所以括號初始化器包含一個收縮轉換,所以程序是格式錯誤的。如果我們取消注釋第 1 行,則隱式定義了移動構造函數並且程序有效。 這種遠距離的詭異動作是極其不幸的。 在這一點上,實現存在分歧。
您可以閱讀問題描述的其余部分。
2017 年在阿爾伯克基的P0859中(在 C++17 發布后)通過了針對此問題的解決方案。 這個問題是一個阻礙,因為它們都能夠有一個constexpr std::swap
(在P0879 中解決)和一個constexpr std::invoke
(在P1065 中解決,它也有 CWG1581 示例),兩者都適用於 C++20。
在我看來,這里最容易理解的示例是 P1065 中指出的 LLVM 錯誤報告中的代碼:
template<typename T> int f(T x) { return x.get(); } template<typename T> constexpr int g(T x) { return x.get(); } int main() { // OK The body of `f' is not required. decltype(f(0)) a; // Seems to instantiate the body of `g' // and results in an error. decltype(g(0)) b; return 0; }
CWG1581 是關於何時定義 constexpr 成員函數的,並且決議確保它們僅在使用時被定義。 在 P0859 之后,以上是格式良好的( b
的類型是int
)。
由於std::swap
和std::invoke
都必須依賴於檢查成員函數(前者中的移動構造/賦值和后者中的調用運算符/代理調用),因此它們都取決於此問題的解決方案。
(由於@NathanOliver)
要允許constexpr
交換函數,您必須檢查 - 在實例化此函數的模板之前 - 交換的類型是可移動構造和可移動分配的。 不幸的是,由於僅在 C++20 中解決了語言缺陷,您無法檢查它,因為就編譯器而言,相關成員函數可能尚未定義。
<algorithm>
函數標記為constexpr
。constexpr std::swap()
和constexpr std::invoke()
- 請參閱上面的解釋。std::swap
和其他一些結構,這被 C++17 接受。std::swap()
constexpr 。std::invoke()
修復也是如此。如果您不檢查移動可構造性和移動可分配性,而是直接檢查某些其他類型的特性,特別是確保這一點,則可以使用constexpr
交換。 例如,只有原始類型,沒有類或結構。 或者,理論上,您可以放棄檢查並只處理您可能遇到的任何編譯錯誤,以及編譯器之間的不穩定行為切換。 無論如何,不要用那種東西替換std::swap()
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.