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

我试图了解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。

我做了一些研究,这是我的问题:

  1. 我认为编译错误是由于缺少queue<T>的{​​{1}}构造函数而导致的。请参见initializer_listhttp://www.cplusplus.com/reference/vector/vector/vector/vector<T>http://www.cplusplus.com/reference/queue/queue/queue/我正确吗?
  2. 现在,对于从queue<T>V0的所有向量,我了解了V6V0V1。有人可以帮助我理解V4V2V3V5吗?
  3. 我不太了解V6Q0。有人可以帮我吗?

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

FENGSHENGZHUO 回答:试图了解C ++ STL容器的初始化

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

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构造函数。但是,括号初始列表中的“值”本身就是另一个括号初始列表。 int无法从2元素的braced-init-list初始化,因此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的{​​{1}}构造函数采用initializer_list,这肯定很奇怪)。如果T有效,那么T t = {some_val};也会有效。

initializer_list<T> il = {{some_val}};

这些与1、2和3相同。列表初始化通常称为“统一初始化”,因为直接使用braced-init-list与使用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 之间几乎没有区别。唯一不同的是,是否选择了显式构造函数,或者您是在= braced-init-list中使用括号初始列表中的单个值。


auto的{​​{1}}构造函数未“丢失”。它不是故意存在的,因为queue不是容器。这是容器 adapter 类型。它存储一个容器,并使该容器的接口适应于队列操作:推送,弹出和查看。

因此,都不应该起作用。

initializer_list

这将使用常规的旧重载分辨率调用queue的构造函数,就像queue<int> Q0 ({ 10,20 }); 一样。唯一的区别是,它选择的构造函数是采用队列的容器类型的构造函数。由于您未指定容器,因此它使用默认值:queue<int>,它可以由两个整数的花括号初始化列表构造。

V0

std::deque<int>的情况相同。 queue<int> Q5 {{ 10,20 }}; 上没有initializer_list构造函数,因此它的作用与V2完全相同:使用重载分辨率选择一个构造函数,该构造函数的参数可以采用2个整数的大括号初始列表。

本文链接:https://www.f2er.com/2831949.html

大家都在问