![](/img/trans.png)
[英]Why can I call a non-constexpr function inside a constexpr function?
[英]Non-constexpr variant member call compiling inside constexpr class member function with condition - why?
#include <variant>
struct S {
constexpr auto f() -> void {
// deleting the next line creates an error
if(std::holds_alternative<int>(m_var))
m_var.emplace<double>(5.0);
}
std::variant<int, double> m_var;
};
int main() {
return 0;
}
std::variant
有一個非constexpr
成員函數emplace()
。 通常,您不能在constexpr
函數中使用它。 但是,如果您通過在該類型上使用std::holds_alternative()
的條件包圍該調用,則可以。 還有其他 constexpr 函數,只要它們是該類中的成員函數。
我很難理解發生了什么。 我的第一反應是說這是一個錯誤。 該條件不可能比根本沒有條件更 constexpr。 但也許這為時過早。 任何人都可以對此有所了解嗎? 為什么emplace()
不是 constexpr 但(相等類型)賦值是?
編輯:也許要擴展一點:一種猜測是所涉及的變體的構造函數和析構函數可能是非 constexpr,這就是為什么emplace
等不是。 但有趣的是,即使您明確濫用非 constexpr 構造函數,您也可以使用這樣的條件將函數編譯為 constexpr。 這使該論點無效。
神箭:這里。
你實際上不需要深入研究std::variant
來推理這個。 這主要是關於常量表達式的工作原理。 constexpr
函數必須以允許在常量表達式中求值的方式定義。 對於某些參數,我們是否遇到無法出現在常量表達式中的內容並不重要,只要對於其他參數我們獲得有效的常量表達式即可。 標准中明確提到了這一點,例如
[dcl.constexpr]
5對於既不是默認值也不是模板的 constexpr 函數或 constexpr 構造函數,如果不存在參數值使得函數或構造函數的調用可以是核心常量表達式的計算子表達式,或者對於構造函數,則是常量初始值設定項對於某些對象([basic.start.static]),程序格式錯誤,不需要診斷。 [ 例子:
constexpr int f(bool b) { return b ? throw 0 : 0; } // OK constexpr int f() { return f(true); } // ill-formed, no diagnostic required struct B { constexpr B(int x) : i(0) { } // x is unused int i; }; int global; struct D : B { constexpr D() : B(global) { } // ill-formed, no diagnostic required // lvalue-to-rvalue conversion on non-constant global };
— 結束示例 ]
看看f(bool)
是一個有效的constexpr
函數嗎? 即使不能在常量表達式中計算throw
表達式,它仍然可以出現在constexpr
函數中。 只要持續評估沒有達到它就沒有問題。
如果沒有可以在常量表達式中使用constexpr
函數的參數集,則程序格式錯誤。 這種格式錯誤的程序不需要診斷,因為僅從函數定義中檢查這種情況通常是難以處理的。 然而,它是無效的 C++,即使編譯器沒有引發錯誤。 但在某些情況下,它可以被檢查,因此編譯器可能有義務提出診斷。
沒有條件的f
屬於此類格式錯誤的結構。 無論f
怎么調用,它的執行都會導致調用emplace
,它不能出現在常量表達式中。 但是它很容易檢測到,因此您的編譯器會告訴您這是一個問題。
帶有條件的第二個版本不再無條件地調用emplace
。 現在是有條件的。 條件本身依賴於constexpr
函數,因此它不會立即constexpr
。 一切都將取決於函數的自變量( this
包括)。 所以它不會立即引發錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.