对于下面的代码,编译器是否有任何原因会选择非显式构造函数..
struct S {
S() = default;
explicit S(S & cp) {
std::cout << "explicit" << std::endl;
}
S(const S & cp) {
std::cout << "copy" << std::endl;
};
};
int main() {
S s1;
S s2 = {s1};
}
来自 https://en.cppreference.com/w/cpp/language/list_initialization,它说对于 copy-list-ini...显式和非显式构造函数都被考虑,但只有非显式构造函数可以被称为
S s2 = {s1};
这是由构造函数初始化(...相同或派生类类型),它由 [over.match.ctor]/1 [emphasis 我的]:
控制当类类型的对象被直接初始化、从相同或派生类类型的表达式([dcl.init])复制初始化或默认初始化时,重载解析选择构造函数。对于不在复制初始化上下文中的直接初始化或默认初始化,候选函数是正在初始化的对象的类的所有构造函数。 对于复制初始化(包括复制初始化上下文中的默认初始化),候选函数是该类的所有转换构造函数 ([class.conv.ctor])。
显式构造函数不是转换构造函数,根据 [class.conv.ctor]/1:
非显式构造函数 ([dcl.fct.spec]) 指定从其参数类型(如果有)到其类类型的转换。这样的构造函数称为转换构造函数。
因此,
explicit S(S & cp)
不是通过构造函数表达式 S s2 = {s1}
进行初始化的可行候选者。
在复制列表初始化中,不是通过构造函数(相同或派生类类型)进行初始化,显式构造函数是可行的候选者,如果选择作为最佳可行的候选者,将导致程序格式不正确,根据[over.match.list]/1:
[...] 在复制列表初始化中,如果选择显式构造函数,则初始化格式错误。