too*_*zzy 12 c++ object-construction c++11 stdinitializerlist
在这样的代码中:
#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{{}};
}
Run Code Online (Sandbox Code Playgroud)
为什么调用std::initializer_list<int>构造函数的规范?如果我们定义构造函数,它会产生歧义编译错误std::initializer_list<double>.这种结构的规则是什么?为什么std::initializer_list数字作为模板参数如此具体?
{}为标量类型(如int,double,char*等)是单位转换.
{}除了std::initializer_list(例如std::string)的特化之外的类类型是用户定义的转换.
前者胜过后者.
如果一个类有一个初始化列表构造函数,那么就{whatever goes here}意味着将{whatevergoeshere}参数作为参数传递给当前的构造函数(如果没有初始化列表构造函数,则whatever goes here作为参数传递).
因此,让我们简化设置并忽略其他构造函数,因为显然编译器并不关心它们
void f(std::initializer_list<std::string> s);
void f(std::initializer_list<int> l);
Run Code Online (Sandbox Code Playgroud)
因为f({{}})我们有这个规则
否则,如果参数类型是std :: initializer_list并且初始化列表的所有元素都可以隐式转换为X,则隐式转换序列是将列表元素转换为X所需的最差转换,或者如果初始化列表没有元素,标识转换.即使在调用initializer-list构造函数的上下文中,此转换也可以是用户定义的转换.
这里我们有一个元素{},它需要用户定义的转换来初始化std::string而不需要转换(标识)int.因此,int被选中.
对于f({{{}}})元素是{{}}.可以转换成int?规则是
- 如果初始化列表有一个本身不是初始化列表的元素,则隐式转换序列是将元素转换为参数类型所需的序列
- ...
- 在除上述列举之外的所有情况下,都不可能进行转换.
可以转换成std::string?是的,因为它有一个具有std::initializer_list<char> init参数的初始化列表构造函数.因此,std::string这次选择.
不同之处A a3({})在于,在这种情况下,它不是列表初始化,而是带有{}参数的"正常"初始化(请注意,由于缺少外部大括号而少了一个嵌套).这里我们的两个f功能被称为{}.由于两个列表都没有元素,因此我们都有身份转换,因此存在歧义.
在这种情况下,编译器也将考虑f(int)并与其他两个函数建立联系.但是应用一个int决胜论者宣称 - 参数比参数更差initializer_list.所以你有一个偏序{int} < {initializer_list<string>, initializer_list<int>},这是模糊性的原因,因为最好的一组转换序列不包含一个候选者,而是两个.
| 归档时间: |
|
| 查看次数: |
2030 次 |
| 最近记录: |