vbs*_*stb 7 c++ initializer-list language-lawyer c++11
struct X
{
X() { std::cout << "default ctor" << std::endl; }
};
int main()
{
X({});
}
Run Code Online (Sandbox Code Playgroud)
打印出来
default ctor
Run Code Online (Sandbox Code Playgroud)
这是有道理的,因为空括号值初始化对象(我认为).然而,
struct X
{
X() { std::cout << "default ctor" << std::endl; }
X(std::initializer_list<int>) { std::cout << "initializer list" << std::endl; }
};
int main()
{
X({});
}
Run Code Online (Sandbox Code Playgroud)
为此,我得到了
initializer list
Run Code Online (Sandbox Code Playgroud)
我没有发现这种行为如此奇怪,但我并不完全相信.对此有什么规定?
这种行为是否写在标准的某些部分?
Bri*_*ian 12
要查看实际情况,请声明复制和移动构造函数,在C++ 14模式或更早版本中进行编译,并禁用复制省略.
输出:
default ctor
move ctor
Run Code Online (Sandbox Code Playgroud)
在第一个片段中,编译器查找X带有单个参数的构造函数,因为您提供了单个参数.这些都是复制和移动的构造,X::X(const X&)并且X::X(X&&),该编译器将隐式声明的你,如果你不自己申报.然后,编译器使用默认构造函数转换{}为X对象,并将该X对象传递给移动构造函数.(你必须使用fno-elide-constructors才能看到这一点,否则编译器将忽略此移动,并且在C++ 17中,复制省略成为强制性的.)
在第二个片段中,编译器现在可以选择转换{}为X(然后调用移动构造函数),或者转换{}为std::initializer_list<int>(然后调用初始化列表构造函数).根据[over.ics.list] /6.2,从转换{}到X,它调用默认构造函数,是一个用户定义的转换,而如[over.ics.list/4时,从转换{}到std::initializer_list<int>是单位转换.标识转换优于用户定义的转换,因此编译器调用初始化列表构造函数.
这种行为是否写在标准的某些部分?
当然.这完全由[dcl.init]/16中的规则决定,强调我的匹配你的初始化程序:
初始化器的语义如下.目标类型是要初始化的对象或引用的类型,源类型是初始化表达式的类型.如果初始化程序不是单个(可能带括号的)表达式,则不定义源类型.
如果初始化程序是(非括号的)braced-init-list,则对象或引用是列表初始化的([dcl.init.list]).
[...]
如果目标类型是(可能是cv限定的)类类型:
- 如果初始化是直接初始化,或者它是复制初始化,其中源类型的cv-nonqualified版本与目标类相同的类或派生类,则考虑构造函数.枚举适用的构造函数([over.match.ctor]),并通过重载决策([over.match])选择最佳构造函数.调用所选的构造函数来初始化对象,初始化表达式或表达式列表作为其参数.如果没有构造函数适用,或者重载决策是不明确的,则初始化是错误的.
- [...]
您提供带括号的空brace-init-list,因此只应用后一个项目符号.考虑构造函数,在第一种情况下,我们最终从默认初始化中进行复制初始化X.在后一种情况下,initializer_list选择c'tor作为更好的匹配.选择此重载的规则在[over.ics.list]中指定:
当参数是初始化列表([dcl.init.list])时,它不是表达式,并且特殊规则适用于将其转换为参数类型.
如果参数类型是std :: initializer_list或"X的数组"并且初始化列表的所有元素都可以隐式转换为X,则隐式转换序列是将列表元素转换为X所需的最差转换.即使在调用初始化列表构造函数的上下文中,转换也可以是用户定义的转换.
否则,如果参数是非聚合类X并且每个[over.match.list]的重载决策选择X的单个最佳构造函数来从参数初始化列表执行类型X的对象的初始化,则隐式转换序列是用户定义的转换序列.如果多个构造函数是可行的但没有一个比其他构造函数更好,则隐式转换序列是不明确的转换序列.除了[over.best.ics]中所述之外,允许用户定义的转换将初始化列表元素转换为构造函数参数类型.
| 归档时间: |
|
| 查看次数: |
1633 次 |
| 最近记录: |