c++ - 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?

标签 c++ c++14 language-lawyer initializer-list

当使用包含多个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]). [...]

查看 [over.match] 我们有 [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.

关于c++ - 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53120718/

相关文章:

c++ - 这里是否需要类型名称?

c++ - 严格别名规则是否适用于函数调用?

c++ - 在 magick++ api 中调整大小的默认过滤器类型

c++ - 如何在 DevC++ 中运行程序并在文件路径中使用空格?

c++ - 使用就地 lambda 进行复杂的初始化,尤其是 const

c++ - 替代模板变量?

c++ - 编译、静态初始化和静态库的问题

c++ - Rust 迭代器和 C++ 迭代器之间的主要区别是什么?

c++ - 如何从一个文件中读取,然后继续从cin中读取?

c++ - std::is_trivially_equality_comparable_v<T>