标准是否定义了带有多余大括号的列表初始化(例如 T{{{10}}})?

Does the standard define list initialization with superfluous braces (e.g. T{{{10}}})?

当使用包含多个braced-init-list的braced-init-list时,标准为B、C和D定义的规则是什么?

对于 B,我相信这种情况在标准中被定义为具有单个元素的大括号初始化列表,因此它直接调用 Test(int) 而没有临时 - 但我无法找到位置。

对于 C 和 D,我不确定这是否是未定义的行为。

我也对使用多个元素时会发生什么感兴趣,即 {{{1, 2}}} 以及这是否会改变 B、C 或 D 的行为?

#include <iostream>

struct Test {
    Test(const int a) {
        // A and B call this
    }

    Test(Test&& test) = delete;
    Test(const Test& test) = delete;
};

int main()
{
    Test a{1}; // calls Test(int)
    Test b{{2}}; // B
    Test c{{{3}}}; // C
    Test d{{{{4}}}}; // D
    // Test e{a}; error, deleted copy constructor
    // Test f{Test{0}}; error, deleted move constructor
    return 0;
}

GCC g++ my_prog.cpp 仅针对 C 和 D 给出错误:

my_prog.cpp: In function 'int main()':
my_prog.cpp:16:17: error: too many braces around initializer for 'int' [-fpermissive]
     Test c{{{3}}};
                 ^
my_prog.cpp:4:14: note:   initializing argument 1 of 'Test::Test(int)'
     Test(int a) {
          ~~~~^

当你有

Test b{{2}}; 

[dcl.init.list]/3.7 状态。

Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution ([over.match], [over.match.list]). [...]

并查看 [[=​​50=]] 我们有 [over.match.ctor]/1

When objects of class type are direct-initialized, copy-initialized from an expression of the same or a derived class type ([dcl.init]), or default-initialized, overload resolution selects the constructor. For direct-initialization or default-initialization that is not in the context of copy-initialization, the candidate functions are all the constructors of the class of the object being initialized. For copy-initialization (including default initialization in the context of copy-initialization), the candidate functions are all the converting constructors ([class.conv.ctor]) of that class. The argument list is the expression-list or assignment-expression of the initializer.

所以我们考虑构造函数,找到

Test(const int a)

然后我们使用元素 {2} 作为 a 的初始值设定项,它使用 [dcl.init.list]/3.9

Otherwise, if the initializer list has a single element of type E and either T is not a reference type or its referenced type is reference-related to E, the object or reference is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization); if a narrowing conversion (see below) is required to convert the element to T, the program is ill-formed.

Test c{{{3}}};
// and
Test d{{{{4}}}};

我们做同样的事情。我们查看构造函数,发现

Test(const int a)

作为唯一可行的。当我们这样做并尝试初始化 a 时,我们再次查看 [dcl.init.list]/3.9 但它不适用于此处。 {{3}}{{{4}}} 不是具有单一类型 E 的初始化列表。 braced-init-list 没有类型所以我们必须继续在 [dcl.init.list]/3 中列出。当我们这样做时,我们不会遇到任何其他匹配的东西,直到 [dcl.init.list]/3.12

Otherwise, the program is ill-formed.