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我不觉得这种行为那么奇怪,但我并不完全相信。这个规则是什么?
这种行为是否写入了标准的某个部分?
发布于 2018-02-05 07:39:42
这种行为是否写入了标准的某个部分?
当然了。所有这些都是由[dcl.init]/16中的规则决定的,强调我的规则以匹配您的初始化程序:
初始化器的语义如下。目标类型是正在初始化的对象或引用的类型,源类型是初始化器表达式的类型。如果初始化器不是单个(可能是括号大小)表达式,则不定义源类型。
- **If the initialization is direct-initialization**, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, **constructors are considered**. The applicable constructors are enumerated ([over.match.ctor]), and the best one is chosen through overload resolution ([over.match]). The constructor so selected is called to initialize the object, with the initializer expression or expression-list as its argument(s). If no constructor applies, or the overload resolution is ambiguous, the initialization is ill-formed.
- [...]
您提供一个括号大小的空大括号-init-列表,所以只适用于后一个项目。考虑构造函数,在第一种情况下,我们将从默认初始化的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中有说明。
发布于 2018-02-05 07:59:58
要了解实际情况,请声明复制和移动构造函数,以C++14模式或更早的模式编译,并禁用复制省略。
Coliru链接
输出:
default ctor
move ctor在第一个片段中,编译器查找接受单个参数的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>的转换是身份转换。身份转换优于用户定义的转换,因此编译器调用初始化程序列表构造函数。
https://stackoverflow.com/questions/48617690
复制相似问题