简体   繁体   English

std :: initializer_list构造函数

[英]std::initializer_list constructor

In code like this: 在这样的代码中:

#include <iostream> 
#include <initializer_list>
#include <string>

struct A 
{
  A() { std::cout << "2" << std::endl; }
  A(int a) { std::cout << "0" << std::endl; }
  A(std::initializer_list<std::string> s) { std::cout << "3" << std::endl; }
  A(std::initializer_list<int> l) { std::cout << "1" << std::endl; } 
};

int main() 
{ 
 A a1{{}}; 
} 

Why does it call std::initializer_list<int> specification of constructor? 为什么调用构造函数的std::initializer_list<int>规范? It'll generate ambiguity compilation error if we define, for example, constructor with std::initializer_list<double> . 如果我们使用std::initializer_list<double>定义构造函数,它将生成歧义编译错误。 What are the rules of such construction and why is it so specific about std::initializer_list with number as template argument? 这种构造的规则是什么?为什么std::initializer_list与数字作为模板参数如此具体?

{} to a scalar type (such as int , double , char* , etc.) is the identity conversion. {}到标量类型(例如intdoublechar*等)是标识转换。

{} to a class type other than a specialization of std::initializer_list (eg, std::string ) is a user-defined conversion. {}比的特殊化其他的类类型std::initializer_list (例如, std::string )是一个用户定义的转换。

The former beats the latter. 前者胜过后者。

If a class has an initializer list constructor, then {whatever goes here} means to pass {whatevergoeshere} as argument to the present constructors (if there are no initializer list constructors, then whatever goes here are passed as arguments). 如果一个类有一个初始化列表构造函数,那么{whatever goes here}意味着将{whatevergoeshere}作为参数传递给当前构造函数(如果没有初始化列表构造函数,那么whatever goes here都将作为参数传递)。

So let's simplify the setting and ignore the other constructors, because apparently the compilers don't care about them 因此,让我们简化设置并忽略其他构造函数,因为显然编译器并不关心它们

void f(std::initializer_list<std::string> s);
void f(std::initializer_list<int> l); 

For f({{}}) we have this rule 对于f({{}})我们有这个规则

Otherwise, if the parameter type is std​::​initializer_list and all the elements of the initializer list can be implicitly converted to X, the implicit conversion sequence is the worst conversion necessary to convert an element of the list to X, or if the initializer list has no elements, the identity conversion. 否则,如果参数类型是std :: initializer_list并且初始化列表的所有元素都可以隐式转换为X,则隐式转换序列是将列表元素转换为X所需的最差转换,或者如果初始化列表没有元素,标识转换。 This conversion can be a user-defined conversion even in the context of a call to an initializer-list constructor. 即使在调用initializer-list构造函数的上下文中,此转换也可以是用户定义的转换。

Here we have a single element {} and it needs a user defined conversion to initialize std::string and no conversion (identity) for int . 这里我们有一个单独的元素{} ,它需要一个用户定义的转换来初始化std::string而不需要int转换(标识)。 Therefore, int is chosen. 因此,选择int

For f({{{}}}) the element is {{}} . 对于f({{{}}}) ,元素为{{}} Can it be converted to int ? 它可以转换为int吗? The rule is 规则是

  • if the initializer list has one element that is not itself an initializer list, the implicit conversion sequence is the one required to convert the element to the parameter type 如果初始化列表有一个本身不是初始化列表的元素,则隐式转换序列是将元素转换为参数类型所需的序列
  • ... ...
  • In all cases other than those enumerated above, no conversion is possible. 在除上述列举之外的所有情况下,都不可能进行转换。

Can it be converted to std::string ? 它可以转换为std::string吗? Yes, because it has an initializer list constructor that has a std::initializer_list<char> init parameter. 是的,因为它有一个初始化列表构造函数,它具有std::initializer_list<char> init参数。 Therefore, std::string is chosen this time. 因此,这次选择了std::string


The difference to A a3({}) is that in such a case, it's not list initialization, but a "normal" initialization with a {} argument (note that one less nesting because of the missing outer braces). A a3({})的区别在于,在这种情况下,它不是列表初始化,而是具有{}参数的“正常”初始化(请注意,由于缺少外部大括号,因此少了一个嵌套)。 Here our two f -functions are called with {} . 这里我们两家f -functions被称为与{} And since both lists have no elements, for both we have identity conversions and therefore an ambiguity. 由于两个列表都没有元素,因此我们都有身份转换,因此存在歧义。

The compiler in this case will also consider f(int) and get a tie with the other two functions. 在这种情况下,编译器也将考虑f(int)并与其他两个函数建立联系。 But a tie-breaker would apply that declares the int -parameter worse than the initializer_list parameters. 但是应用一个决胜论者会声明int参数比initializer_list参数更糟糕。 So you have a partial order {int} < {initializer_list<string>, initializer_list<int>} , which is the reason for ambiguity, as the best group of conversion sequences does not contain a single candidate, but two. 因此,您有一个部分顺序{int} < {initializer_list<string>, initializer_list<int>} ,这是歧义的原因,因为最佳转换序列组不包含单个候选,而是两个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM