显式复制构造函数不允许Foo foo = bar;
之类的内容,并将复制用法强制为Foo foo(bar);
。此外,显式复制构造函数还禁止通过函数的值返回对象。但是,我尝试用大括号替换副本初始化,如此
struct Foo
{
Foo() = default;
explicit Foo(const Foo&) = default;
};
int main()
{
Foo bar;
Foo foo{bar}; // error here
}
我收到了错误(g ++ 5.2)
错误:没有匹配函数来调用'Foo :: Foo(Foo&)'
或(clang ++)
错误:struct initializer中的多余元素
删除explicit
使代码在g ++下可编译,clang ++仍然失败并出现相同的错误(感谢@Steephen)。这里发生了什么?统一初始化是否被视为初始化列表构造函数(胜过所有其他构建函数)?但如果是这种情况,为什么程序在复制构造函数非显式时编译?
答案 0 :(得分:24)
在C ++ 14最终确定之后,您遇到了Core issue 1467分辨率解决的案例。
让我们首先注意,类foo
是一个聚合。您的代码正在为foo
执行 direct-list-initialization 。列表初始化的规则在[8.5.4p3]中。
在C ++ 14中(引自N4140,最接近公布标准的工作草案),上述段落始于:
定义了
T
类型的对象或引用的列表初始化 如下:
- 如果
T
是聚合,则执行聚合初始化(8.5.1)。[...]
因此,如果您的类是聚合,则编译器会尝试进行聚合初始化,但这会失败。
这被认为是一个问题,并在工作草案中得到修复。从当前版本N4527引用,上述段落现在以:
开头定义了
T
类型的对象或引用的列表初始化 如下:
- 如果
T
是类类型且初始值设定项列表包含 cvU
类型的单个元素,则其中U
为T
或一个派生自T
的类, object从该元素初始化(通过复制初始化) copy-list-initialization,或者直接初始化 直接一览初始化)。- 否则,如果
T
是一个字符数组,并且初始化列表的单个元素是一个适当类型的字符串文字 (8.5.2),按照该部分的描述进行初始化。- 否则,如果
T
是聚合,则执行聚合初始化(8.5.1)。[...]
您的示例现在属于第一个项目符号点描述的情况,并且foo
使用默认的复制构造函数 direct-list-initialized (无论它是否为explicit
因为它是直接初始化的。)
即...如果编译器在缺陷报告中实现了解决方案。
explicit
相关的错误。explicit
并不重要)。bar
下的波形 - 看起来像IntelliSense使用的EDG编译器也没有更新)。更新:由于这个答案是写的,工作草案已经进一步修改了几个与问题中的例子和上述解释相关的方式:
- 如果
T
是汇总类,则[...]
explicit
构造函数(甚至是默认值)的类不再是聚合。这并没有改变以下事实:在实施所有更改之后,问题中的示例旨在工作,无论是否有explicit
;值得一提的是,使其发挥作用的潜在机制略有改变。
请注意,所有这些更改都是缺陷报告的解决方案,所以当编译器处于C ++ 14和C ++ 11模式时,它们应该适用。