简体   繁体   English

为什么我不能使用任意大括号嵌套来构造大多数类?

[英]Why can't I use an arbitrary nesting of braces to construct most classes?

Given the following code:给定以下代码:

struct A;

struct B {
    B() {}
    B(A &&) {}
};

struct A {
    A() {}
    A(B &&) {}
};

Then I can use as many braces as I want to construct A or B .然后我可以使用尽可能多的大括号构造AB

// 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{{{{{}}}}};

Similarly, given同样,给定

struct C {
    C(std::initializer_list<C>) {}
};

then I can also use as many braces as I want然后我也可以使用任意多的牙套

// 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{{{{{}}}}};

Why doesn't the same argument work for a truly boring type?为什么同样的论点不适用于真正无聊的类型?

struct D {
};

or, rewritten for clarity:或者,为清楚起见重写:

struct D {
    D() {}
    D(D &&) {}
};

This fails even on这甚至失败了

auto k = D{{}};

Why does this not default construct a D with the innermost braces, and then pass that rvalue on to the move constructor of D ?为什么这不默认用最里面的大括号构造一个D ,然后将该右值传递给D的移动构造函数?

See it live: https://godbolt.org/z/E763EPGh1现场观看:https://godbolt.org/z/E763EPGh1

There's a special case that precludes D{{}} .有一种特殊情况排除了D{{}} It's a very particular set of conditions, so I imagine it's there specifically to prevent this exact recursion.这是一组非常特殊的条件,所以我想它是专门用来防止这种精确递归的。

[over.best.ics]/4 However, if the target is [over.best.ics]/4但是,如果目标是
(4.1) — the first parameter of a constructor (4.1) — 构造函数的第一个参数
... ...
and the constructor... is a candidate by并且构造函数...是候选人
... ...
(4.5) — the second phase of [over.match.list] when the initializer list has exactly one element that is itself an initializer list, and the target is the first parameter of a constructor of class X , and the conversion is to X or reference to cv X , (4.5) — [over.match.list]的第二阶段,当初始化列表恰好有一个元素本身就是初始化列表,并且目标是 class X的构造函数的第一个参数,并且转换为X或参考cv X
user-defined conversion sequences are not considered.不考虑用户定义的转换序列。

D{{}} is a list-initialization. D{{}}是一个列表初始化。 D(D&&) constructor is considered by the second phase of it (the first phase looks at initializer-list constructors, like C(std::initializer_list<C>) in your second example). D(D&&)构造函数由它的第二阶段考虑(第一阶段查看初始化列表构造函数,如第二个示例中的C(std::initializer_list<C>) )。 But for it to be viable, there needs to be an implicit conversion from {} to D&& , and [over.best.ics]/4 suppresses it.但要使其可行,需要从{}D&&的隐式转换,并且[over.best.ics]/4会抑制它。

Your two versions of D is in fact unequal.你的两个版本的D实际上是不相等的。 Suppose you have假设你有

struct E {};
struct F {
    F() {}
    F(F&&) {}
};

auto e = E{{}};
auto f = F{{}};

e fails because E is an aggregate . e失败,因为E是一个聚合 Each comma separated element within the outermost {} is used to initialize a member in E .最外层{}中的每个逗号分隔元素都用于初始化E中的成员。 Since E contains nothing, you have too many initializers for E .由于E不包含任何内容,因此E的初始化程序太多。

As @IgorTandetnik mentioned, f fails specifically because it is an exception in implicit conversions: a nested initializer list cannot be used to initialize the reference in copy or move constructors.正如@IgorTandetnik 提到的, f特别失败,因为它是隐式转换中的一个例外:嵌套的初始化列表不能用于初始化复制或移动构造函数中的引用。 This is true even if the inner initializer list contains more elements即使内部初始化列表包含更多元素也是如此

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

Presumably, this is to prevent infinite recursions想必是为了防止无限递归

These rules prevent more than one user-defined conversion from being applied during overload resolution, thereby avoiding infinite recursion.这些规则防止在重载解析期间应用多个用户定义的转换,从而避免无限递归。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么嵌套类时不能从内部 class 访问外部 class 的私有成员? - Why can't I access private members of the outer class from the inner class when nesting classes? 我可以用花括号构建一个链表吗? - Can i construct a linked list with curly braces? 为什么我不能在Qt中使用普通的C ++类 - why I can't use normal C++ classes with Qt 为什么我可以使用初始化列表来构造对象? - Why I can use initialtion list to construct object? 为什么我不能从迭代器构造一个 std::span ? - why can't I construct an std::span from iterators? 为什么我不能从 char* 构造 wstring - Why I can't construct a wstring from char* 为什么我不能在 C++ 中构造一个带有 NULL char* 的字符串? - Why can't I construct a string with a NULL char* in C++? 为什么我不能在类中定义变量? - Why can't I define variables in classes? 为什么我不能在VS2008的类中使用静态成员,例如静态结构? - Why can't I use static members, for example static structures, in my classes in VS2008? 为什么不能使用带有花括号的auto初始化值并将其传递给此函数 - Why can't I initialize a value using braces with auto and pass it into this function
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM