fre*_*low 5 c++ syntax initialization initializer-list c++11
以下三个初始化与std::initializer_lists 之间有什么区别?
std::vector<int> a{ 2, 3, 5, 7};
std::vector<int> b( { 2, 3, 5, 7} );
std::vector<int> c = { 2, 3, 5, 7};
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,std::vector只是一个占位符,但我对一般答案感兴趣.
让我们抽象一下std::vector。并称之T。
T t{a, b, c};
T t = { a, b, c };
T t({a, b, c});
Run Code Online (Sandbox Code Playgroud)
前两种形式是列表初始化(它们之间唯一的区别是如果T是一个类,则explicit禁止调用第二个构造函数。如果调用其中一个,则程序将变得格式错误)。最后一种形式只是普通的直接初始化,正如我们从 C++03 中知道的那样:
T t(arg);
Run Code Online (Sandbox Code Playgroud)
出现{a, b, c}as arg意味着构造函数调用的参数是大括号初始值设定项列表。第三种形式没有列表初始化所具有的特殊处理。即使大括号初始化列表只有 1 个参数,那里也T 必须是类类型。我很高兴在这种情况下我们在发布 C++11 之前制定了明确的规则。
至于第三个调用什么构造函数,让我们假设
struct T {
T(int);
T(std::initializer_list<int>);
};
T t({1});
Run Code Online (Sandbox Code Playgroud)
由于直接初始化只是对重载构造函数的调用,因此我们可以将其转换为
void ctor(int);
void ctor(std::initializer_list<int>);
void ctor(T const&);
void ctor(T &&);
Run Code Online (Sandbox Code Playgroud)
我们可以使用这两个尾随函数,但如果我们选择这些函数,我们将需要用户定义的转换。为了初始化T ref参数,将使用列表初始化,因为这不是带括号的直接初始化(因此参数初始化相当于T ref t = { 1 })。前两个函数是完全匹配的。然而,标准表示,在这种情况下,当一个函数转换为 ,std::initializer_list<T>而另一个函数没有转换时,则前一个函数获胜。ctor因此在这种情况下,将使用第二个。请注意,在这种情况下,我们不会仅使用第一个初始化器列表向量进行两阶段重载决策 - 只有列表初始化才会这样做。
对于前两个,我们将使用列表初始化,它将执行上下文相关的操作。如果T是一个数组,它将初始化一个数组。以这个类为例
struct T {
T(long);
T(std::initializer_list<int>);
};
T t = { 1L };
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我们进行两阶段过载解决。我们首先只考虑初始化列表构造函数,并查看是否有一个匹配,作为参数,我们采用整个大括号初始化列表。第二个 ctor 匹配,所以我们选择它。我们将忽略第一个构造函数。如果我们没有初始值设定项列表构造函数或者没有匹配项,我们将采用所有构造函数和初始值设定项列表的元素
struct T {
T(long);
template<typename A = std::initializer_list<int>>
T(A);
};
T t = { 1L };
Run Code Online (Sandbox Code Playgroud)
在本例中,我们选择第一个构造函数,因为1L无法转换为std::initializer_list<int>.
| 归档时间: |
|
| 查看次数: |
1633 次 |
| 最近记录: |