提问人:Kishan Parmar 提问时间:8/8/2023 最后编辑:dfribKishan Parmar 更新时间:8/9/2023 访问量:114
为什么编译器总是选择非显式构造函数进行复制列表初始化?
Why compiler always choose non explicit constructor for copy-list-initialization?
问:
对于下面的代码,编译器会选择非显式构造函数吗?
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...显式和非显式构造函数都考虑在内,但只能调用非显式构造函数
答:
程序格式不正确,但存在实现分歧
从CWG 2137开始,您的程序应该格式不正确。然而,这里存在实现分歧,其中 Clang 尚未实现 CWG 2137,而 GCC 已经实现了 CWG 2137 的大部分内容,但可能在上下文 copy-list-initialization(具有同一类的单个元素)中缺少显式构造函数的情况。
错误报告(我刚刚发布了 GCC 报告):
- Clang: 单元素initializer_list调用错误的构造函数 #24186
- GCC:错误110958 - [CWG 2137][accepts-invalid] 使用同一类的单个元素进行复制列表初始化仅将转换构造函数视为可行
规则
[dcl.init.list] 控制列表初始化的规则,以及以下内容:
S s2 = {s1};
自CWG 2137起,[dcl.init.list]/3.7适用:
否则,如果 T 是类类型,则考虑构造函数。枚举适用的构造函数,并通过重载解析([over.match]、[over.match.list])选择最佳构造函数。如果需要缩小转换(见下文)来转换任何参数,则程序格式不正确。
由于没有初始值设定项列表构造函数,因此 [over.match.list]/1.2 适用:
/1.2 否则,或者如果未找到可行的初始值设定项列表构造函数,则再次执行重载解析,其中候选函数是类 T 的所有构造函数,参数列表由初始值设定项列表的元素组成。
在 copy-list-initialization 中,如果选择了显式构造函数,则初始化格式不正确。
由于显式构造函数是更好的匹配,因此应该选择它,之后程序格式不正确,因为 [over.match.list]/1 不允许在 copy-list-initialization 中使用显式构造函数。
GCC 和 Clang 接受该计划都是错误的,但 Clang 由于尚未实施 CWG 2137,而 GCC 则由于缺少 CWG 2137 引入的一些边缘情况而不太适用。
评论
下一个:赋值运算符和初始化
评论
explicit