在下面的代碼類A中有一個私有成員函式f。我想寫一個靜態斷言來檢查這個函式是否可以從當前背景關系中訪問(正如這個問題的評論中所建議的那樣)。
有 3 種類似的情況都是基于requires-expression 的:
class A{ void f(); };
// #1: accepted by all
static_assert( { return requires(decltype(x) a){ a.f(); }; }(A{}) );
// #2: rejected by Clang:
static_assert( { return requires(A a){ a.f(); }; }(nullptr) );
// #3: rejected by all
static_assert( { return requires(A a){ a.f(); }; }(nullptr) );
案例#3(和 Clang 中的#2)被拒絕并出現錯誤:
error: 'f' is a private member of 'A'
演示:https ://gcc.godbolt.org/z/Mxs4P7x8s
為什么 requires-expression 在模板和非模板中的行為不同(案例 #1 和 #3)?哪個編譯器在#2 中是正確的?
uj5u.com熱心網友回復:
雖然https://eel.is/c draft/expr.prim.req.general#1描述了
requires-expression 提供了一種簡潔的方式來表達對模板引數的要求
需求運算式的語法
requires-expression: requires requirement-parameter-list(opt) requirement-body requirement-body: { requirement-seq } requirement-seq: requirement requirement requirement-seq requirement: simple-requirement [...] simple-requirement: expression ; // A simple-requirement asserts the validity of an expression.
允許包含不一定依賴于模板引數的任意運算式的 requires-expressions,這意味著以下是格式良好的:
constexpr bool f() { return requires(int a) { a; }; }
constexpr bool g() { return requires { 0; }; }
static_assert(f());
static_assert(g());
因此,對于在模板化物體之外宣告的 requires-expression,適用與任何運算式相同的規則,#3因此會被所有編譯器正確拒絕(在 requires-expressions 中的運算式背景關系中不會放棄訪問檢查控制) .
#1根據https://eel.is/c draft/expr.prim.req.general#5.sentence-2,所有編譯器也正確實作:
將模板引數替換為 requires-expression 可能會導致在其需求中形成無效型別或運算式,或者違反這些需求的語意約束。在這種情況下, requires 運算式的計算結果為 false;它不會導致程式格式錯誤。
...a.f();在泛型的約束運算式中,a被替換為型別A會導致無效的運算式,因為f()它是私有的且不可見。
最后,#2根據https://eel.is/c draft/expr.prim.req.general#5.sentence-6是 IFNDR :
如果將模板引數替換為需求總是會導致替換失敗,則程式是非良構的;無需診斷。
我們也可以根據https://eel.is/c draft/temp.res.general#6.4爭辯說它是 IFNDR :
該程式格式錯誤,不需要診斷,如果:
- [...]
- 由于不依賴于模板引數的構造,緊隨其定義的模板的假設實體化將是格式錯誤的,或者
因此,#2所有編譯器都正確實作了它,但是當編譯器確實診斷出 IFNDR 違規時,它可以說總是很好,因此是 Clang 的可用性之星。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/417539.html
標籤:
上一篇:泛化積分模板引數
