struct X
{
X() { std::cout << "default ctor" << std::endl; }
};
int main()
{
X({});
}
这打印出来
default ctor
这是有道理的,因为空大括号值初始化了对象(我认为)。
然而,
struct X
{
X() { std::cout << "default ctor" << std::endl; }
X(std::initializer_list<int>) { std::cout << "initializer list" << std::endl; }
};
int main()
{
X({});
}
为此,我得到了
initializer list
我并不觉得这种行为有什么奇怪,但我并不完全相信。这有什么规则吗?
这种行为是否写在标准的某些部分?
要了解实际情况,请声明复制和移动构造函数,在 C++14 模式或更早版本中进行编译,并禁用复制省略。
科利鲁链接 http://coliru.stacked-crooked.com/a/0285e8b07a9dc8b6
Output:
default ctor
move ctor
在第一个片段中,编译器查找构造函数X
需要一个参数,因为您提供了一个参数。这些是复制和移动构造函数,X::X(const X&)
and X::X(X&&)
,如果您自己不声明它们,编译器会为您隐式声明它们。然后编译器会转换{}
to an X
使用默认构造函数的对象,并将其传递给X
对象到移动构造函数。 (您必须使用fno-elide-constructors
看到这一点,否则编译器将省略该移动,并且在 C++17 中,复制省略成为强制性的。)
在第二个片段中,编译器现在可以选择转换{}
to X
(然后调用移动构造函数),或转换{}
to std::initializer_list<int>
(然后调用初始化列表构造函数)。根据[over.ics.list]/6.2,从{}
to X
,它调用默认的构造函数,是一个用户定义的转换,而根据[over.ics.list]/4,来自的转换{}
to std::initializer_list<int>
是身份转换。标识转换比用户定义的转换更好,因此编译器调用初始值设定项列表构造函数。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)