c++ - 试图了解C++ STL容器的初始化

标签 c++ initialization initializer-list

我试图了解C++ STL容器的初始化。这是我的噩梦:

    vector<int> V0 ({ 10, 20 });    // ok - initialized with 2 elements
    vector<int> V1 = { 10, 20 };    // ok - initialized with 2 elements
    vector<int> V2 = {{ 10, 20 }};  // ok - initialized with 2 elements
    vector<int> V3 = {{ 10 }, 20 }; // ok - initialized with 2 elements
    vector<int> V4 { 10, 20 };      // ok - initialized with 2 elements
    vector<int> V5 {{ 10, 20 }};    // ok - initialized with 2 elements
    vector<int> V6 {{ 10 }, 20 };   // ok - initialized with 2 elements
    queue<int> Q0 ({ 10, 20 });     // ok - initialized with 2 elements
 // queue<int> Q1 = { 10, 20 };     // compile error
 // queue<int> Q2 = {{ 10, 20 }};   // compile error
 // queue<int> Q3 = {{ 10 }, 20 };  // compile error
 // queue<int> Q4 { 10, 20 };       // compile error
    queue<int> Q5 {{ 10, 20 }};     // ok - initialized with 2 elements
 // queue<int> Q6 {{ 10 }, 20 };    // compile error

我们正在谈论C++ 11。

我做了一些研究,这是我的问题:
  • 我相信编译错误是由于缺少queue<T>initializer_list构造函数而导致的。参见vector<T>:http://www.cplusplus.com/reference/vector/vector/vector/queue<T>:
    http://www.cplusplus.com/reference/queue/queue/queue/对吗?
  • 现在,对于从V0V6的所有 vector ,我都了解V0V1V4。有人可以帮助我理解V2V3V5V6吗?
  • 我不太了解Q0Q5。有人能帮我吗?

  • 我还在阅读Mike Lui的文章:Initialization in C++ is Seriously Bonkers。我想与大家分享一下,但是有没有一种快速的方法可以帮助我了解这场噩梦? :-)

    最佳答案

    没有任何“噩梦”。您只需要阅读您所写的内容。更具体地说,您必须系统地从外部处理规则。

    vector<int> V0 ({ 10, 20 });
    

    调用vector构造函数(这就是()的意思),并向其传递单个braced-init-list。因此,它将选择一个具有一个值的构造函数,但仅选择其第一个参数可以由包含整数的2元素braced-init-list初始化的构造函数。例如initializer_list<int>包含的vector<int>构造函数。
    vector<int> V1 = { 10, 20 };
    

    列表初始化(当您直接使用braced-init-list初始化事物时会发生这种情况)。在列表初始化规则下,首先考虑带有单个initializer_list参数的所有类型的构造函数。系统尝试直接使用braced-init-list初始化这些构造函数。如果可以使用候选构造函数之一成功,则调用该构造函数。

    显然,您可以从2元素的整数括号初始列表中初始化initializer_list<int>。这是initializer_list中唯一的vector构造函数,因此被调用。
    vector<int> V2 = {{ 10, 20 }};
    

    仍然进行列表初始化。同样,将考虑与braced-init-list中的值匹配的initializer_list构造函数。但是,括号初始列表中的“值”本身就是另一个括号初始列表。不能从2元素的braced-init-list初始化int,因此initializer_list<int>不能初始化{{10, 20}}

    由于无法使用initializer_list构造函数,因此在正常函数重载解析规则下考虑所有构造函数。在这种情况下,(外部)braced-init-list的成员被视为该类型的构造函数的参数。在外部的braced-init-list中只有一个值,因此仅考虑可以使用一个参数调用的构造函数。

    系统将尝试使用内部的braced-init-list初始化所有此类构造函数的第一个参数。还有一个构造函数,其参数可以由2元素的整数支撑初始列表初始化。即,initializer_list<int>构造函数。也就是说,虽然initializer_list<int>不能使用{{10, 20}}进行初始化,但可以仅使用{10, 20}进行初始化。
    vector<int> V3 = {{ 10 }, 20 };
    

    同样,仍然列出初始化。再一次,我们首先尝试将完整的braced-init-list应用到该类型的任何initializer_list构造函数。可以从initializer_list<int>的大括号初始化列表中初始化{{10}, 20}吗?是的。这就是发生的情况。

    为什么这样做?因为任何可复制/移动的T类型始终可以从包含该类型值的大括号初始列表中初始化。也就是说,如果T t = some_val;起作用,那么T t = {some_val};也会起作用(除非T具有使用initializer_listT构造函数,这肯定是很奇怪的)。如果T t = {some_val};起作用,那么initializer_list<T> il = {{some_val}};也会起作用。
    vector<int> V4 { 10, 20 };      // ok - initialized with 2 elements
    vector<int> V5 {{ 10, 20 }};    // ok - initialized with 2 elements
    vector<int> V6 {{ 10 }, 20 };   // ok - initialized with 2 elements
    

    它们与1、2和3相同。列表初始化通常称为“统一初始化”,因为直接使用braced-init-list和= braced-init-list之间几乎没有区别。唯一的区别是,是否选择了显式构造函数,或者您是否正在使用在braced-init-list中具有单个值的auto
    queueinitializer_list构造函数未“丢失”。它不是故意存在的,因为queue不是容器。它是容器适配器类型。它存储一个容器,并使该容器的接口(interface)适应于仅限队列操作:插入,弹出和查看。

    因此,这些都不应该起作用。
    queue<int> Q0 ({ 10, 20 });
    

    就像queue<int>一样,它使用常规的旧的重载分辨率调用V0的构造函数。唯一的区别是,它选择的构造函数是采用队列的容器类型的构造函数。由于未指定容器,因此它使用默认值:std::deque<int>,可以从两个整数的braced-init-list构造它。
    queue<int> Q5 {{ 10, 20 }};
    

    V2相同的情况。 queue上没有initializer_list构造函数,因此它的行为与Q0完全相同:使用重载分辨率来选择一个构造函数,该构造函数的参数可以采用2个整数的大括号初始列表。

    关于c++ - 试图了解C++ STL容器的初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59559162/

    相关文章:

    c++ - 从函数 : What is it compiled down to? 返回花括号初始化器列表

    c++ - 为什么不将 `std::initializer_list` 定义为文字类型?

    c++ - 查找字符串是否包含字符串并处理附加数字

    c++ - 在 emacs 中设置断点时隐藏源缓冲区

    javascript - For循环已初始化但未进入

    Java 数组初始化保证

    c++ - 这个正则表达式是否足以删除 C++ 多行注释?

    c++ - 通过示例学习指针

    c - 在 C 中重新初始化 const char 数组不会给出错误

    c++ - 不能将 std::vector<T> 转换为 std::initializer_list<T> 吗?