給定以下代碼:
struct A;
struct B {
B() {}
B(A &&) {}
};
struct A {
A() {}
A(B &&) {}
};
然后我可以使用盡可能多的大括號來構造A或B.
// default construct A
auto a = A{};
// default construct B, forward to A
auto b = A{{}};
// default construct A, forward to B, forward to A
auto c = A{{{}}};
// etc.
auto d = A{{{{}}}};
auto e = A{{{{{}}}}};
同樣,給定
struct C {
C(std::initializer_list<C>) {}
};
然后我也可以使用任意數量的大括號
// default construct C
auto f = C{};
// construct from initializer_list of one default constructed C
auto g = C{{}};
// construct from initializer_list of one C constructed from empty initializer_list
auto h = C{{{}}};
// etc.
auto i = C{{{{}}}};
auto j = C{{{{{}}}}};
為什么同樣的論點對真正無聊的型別不起作用?
struct D {
};
或者,為了清楚起見重寫:
struct D {
D() {}
D(D &&) {}
};
這甚至失敗了
auto k = D{{}};
為什么這不默認D用最里面的大括號構造 a ,然后將該右值傳遞給 的移動建構式D?
現場觀看:https ://godbolt.org/z/E763EPGh1
uj5u.com熱心網友回復:
有一種特殊情況排除D{{}}. 這是一組非常特殊的條件,所以我想它是專門用來防止這種精確遞回的。
[over.best.ics]/4但是,如果目標是
(4.1) — 建構式的第一個引數
...
并且建構式 ... 是
...
(4.5)的候選物件 — [ over.match.list]當初始化串列恰好有一個元素本身就是初始化串列,并且目標是 class 的建構式的第一個引數X,并且轉換為X或參考cvX時,
用戶定義的轉換序列為不考慮。
D{{}}是一個串列初始化。D(D&&)建構式由它的第二階段考慮(第一階段著眼于初始化串列建構式,就像C(std::initializer_list<C>)在第二個示例中一樣)。但要使其可行,需要從 to 進行隱式轉換{},D&&并且[over.best.ics]/4會抑制它。
uj5u.com熱心網友回復:
您的兩個版本D實際上是不平等的。假設你有
struct E {};
struct F {
F() {}
F(F&&) {}
};
auto e = E{{}};
auto f = F{{}};
e失敗,因為E是一個聚合。最外層中的每個逗號分隔元素{}都用于初始化 中的成員E。由于E不包含任何內容,因此您的E.
正如@IgorTandetnik 提到的,f特別失敗是因為它是隱式轉換中的一個例外:嵌套的初始化串列不能用于初始化復制或移動建構式中的參考。即使內部初始化串列包含更多元素也是如此
struct G {
G() {}
G(G&&) {}
G(int, int) {}
};
struct H {
H() {}
H(G&&) {}
};
auto g = G{{42, 420}}; // also fails
auto h = H{{42, 420}}; // ok
想必這是為了防止無限遞回
這些規則防止在多載決議期間應用多個用戶定義的轉換,從而避免無限遞回。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/417003.html
標籤:
上一篇:GEThttp://localhost:8080/main.jsnet::ERR_CONNECTION_REFUSED部署在Netlify控制臺錯誤
