为什么编译器总是选择非显式构造函数来进行复制列表初始化?

问题描述 投票:0回答:1

对于下面的代码,编译器是否有任何原因会选择非显式构造函数..

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...显式和非显式构造函数都被考虑,但只有非显式构造函数可以被称为

https://godbolt.org/z/YqWWs9jqY

c++ c++11 compiler-construction copy-constructor
1个回答
1
投票
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:

[...] 在复制列表初始化中,如果选择显式构造函数,则初始化格式错误。

© www.soinside.com 2019 - 2024. All rights reserved.