Oli*_*liv 16 c++ language-lawyer c++17
由于构造函数中的B基类子项目的复制构造,以下代码无法使用Gcc和Clang进行编译A:
struct B{
B();
B(const B&) =delete;
};
struct A:B{
A():B(B()){} //=> error: use of deleted function...
};
Run Code Online (Sandbox Code Playgroud)
不过根据[class.base.init]/7:
的表达式列表或支撑-INIT列表在MEM-初始化是根据[dcl.init]用于初始化规则用来初始化指定子对象(或者,在一个委派构造,完整的类对象的情况下)直接初始化.
因此初始化规则对于成员或直接基础是相同的.对于成员子对象,Gcc和Clang不使用已删除的复制构造函数:
struct A2:B{
B b;
A2():b(B()){} //=> OK the result object of B() is b
};
Run Code Online (Sandbox Code Playgroud)
这不是Clang和Gcc的编译器错误吗?是不是B应该省略复制构造函数A()?
有趣的是,即使gcc检查复制结构是否格式正确,它也会忽略此复制构造函数调用,请参阅此处的程序集
这确实很奇怪。首先,无论是否应在此处调用复制构造函数,由于[class.base.init]/7不区分初始化基类和初始化成员,因此两种情况下的行为应该相同。我在标准中找不到任何额外的措辞,这些措辞会以某种方式在基础初始化与成员初始化之间引入不对称性。仅基于这一点,我想说我们可以得出这样或那样的结论:这里存在编译器错误。icc 和 MSVC 似乎至少在初始化基础与初始化成员时表现一致。然而,icc 和 MSVC 对于是否应该接受该代码存在分歧。
\n\n我相信,如果我们再看一下[class.base.init]/7,就可以找到是否应该调用复制构造函数的问题的答案:
\n\n\n\n\nmem-initializer 中的表达式列表或花括号初始化列表用于根据 [dcl.init] 的初始化规则初始化指定的子对象(或者,在委托构造函数的情况下,初始化完整的类对象)直接初始化。[\xe2\x80\xa6]
\n
强调我的。我相信[dcl.init]的相关位应该是[dcl.init]/17.6,我们在其中找到:
\n\n\n\n\n\n
\n\n- \n
如果目标类型是(可能是 cv 限定的)类类型:
\n\n\n
- \n
如果初始值设定项表达式是纯右值,并且源类型的 cv 未限定版本与目标类是同一类,则初始值设定项表达式用于初始化目标对象。[\xe2\x80\xa6]
- \n
否则,如果初始化是直接初始化,或者是复制初始化,其中源类型的 cv 未限定版本与目标类是同一类或目标类的派生类,则考虑构造函数。\ n 枚举适用的构造函数([over.match.ctor]),并通过重载决议选择最好的构造函数([over.match])。[\xe2\x80\xa6]
[\xe2\x80\xa6]
\n
如果要应用 17.6.2,则意味着应调用复制构造函数,这将使 MSVC 成为在此示例中行为正确的唯一主要编译器。但是,我的解释是 17.6.1 一般适用并且 icc 是正确的,即您的代码应该可以编译。这意味着您在这里甚至可能存在 GCC 和 clang 中的两个错误(基类初始化与成员初始化的行为不同 + mem-initializer调用 copy-ctor,尽管它不应该),以及 MSVC\xe2\x80 中的一个错误\xa6
\n| 归档时间: |
|
| 查看次数: |
332 次 |
| 最近记录: |