C++17中拷贝构造函数的继承
Inheritance of copy constructors in C++17
考虑以下示例:
struct Parent
{
Parent ();
Parent (const Parent &);
};
struct Child : public Parent
{
using Parent::Parent;
};
Parent p;
Child c (p);
这取自以下问题:
原来的问题问的是 C++11。在 C++11 中,有一种措辞阻止 Child
获取采用 const Parent&
:
的构造函数
For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same
signature in the class where the using-declaration appears.
N4429 显着改变了继承构造函数的规范,并被认为追溯至 C++11(我认为?)。 N4429 的目的是使基础 class 构造函数可见,就好像它们是派生的 class 构造函数一样,而不是声明派生的 class 构造函数委托给基础 class 构造函数.在N4429的第一个版本中,有如下写法,保留了C++11的限制:
When a using-declaration declares that a class inherits constructors from a base class, the default constructor, copy constructor, and move constructor (if any) of the base class are excluded from the set of introduced declarations.
然而,在这篇论文的更新版本中,P0136R0,这个措辞不再存在,也没有给出原因的解释。该论文再次修订,然后合并到标准中。所以在 C++17 中,我看不到任何阻止上述代码编译的规则。
尽管如此,GCC and Clang both reject it。铿锵声说:
an inherited constructor is not a candidate for initialization from an expression of the same or derived type
但是,我在标准中找不到这样的内容。
此代码在 C++17 中是否格式错误?如果是,为什么?
A constructor inherited from class type C
([class.inhctor.init]) that has a first parameter of type “reference to cv1 P
” (including such a constructor instantiated from a template) is excluded from the set of candidate functions when constructing an object of type cv2 D
if the argument list has exactly one argument and C
is reference-related to P
and P
is reference-related to D
.
参见CWG2356。
我认为 WG21 的规则是:
Base class copy and move constructors brought into a derived class via
a using-declaration are not considered by overload resolution when
constructing a derived class object.
如果 Base 的继承构造函数之一恰好具有与 Derived 的 copy/move 构造函数相匹配的签名,它不会阻止 Derived copy/move 构造函数的隐式生成。
请注意,using A::A;
指令 继承 所有构造函数,包括 copy/move 和 compiler-generated 默认构造函数 A
到派生class(s) 该指令出现的地方;以及 A 的所有构造函数, 除了 copy/move 和 compiler-generated 默认构造函数,在查找派生 class 的构造函数或形成集合时被考虑候选人。
struct B { B(); };
struct D : B { using B::B; };
D d{ B() }; // error: overload resolution found nothing. #1
D d{ D() }; // OK #2
默认的复制构造函数B::B(const B&)
被继承到D
但是这个构造函数不是候选函数。没有 using 指令,程序是 well-formed 因为这被认为是聚合初始化。此外 using-declaration 不会阻止编译器生成 D
的默认 copy/move 构造函数,这就是为什么 #2 可以。
现在为了抑制这个错误,我们应该明确地提供一个user-provided复制构造函数:
struct B{
B();
};
struct D : public B{
using B::B;
B(const B&);
};
D d{ B() }; // OK: overload resolution found constructor matches the argument-list.
考虑以下示例:
struct Parent
{
Parent ();
Parent (const Parent &);
};
struct Child : public Parent
{
using Parent::Parent;
};
Parent p;
Child c (p);
这取自以下问题:
原来的问题问的是 C++11。在 C++11 中,有一种措辞阻止 Child
获取采用 const Parent&
:
For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the class where the using-declaration appears.
N4429 显着改变了继承构造函数的规范,并被认为追溯至 C++11(我认为?)。 N4429 的目的是使基础 class 构造函数可见,就好像它们是派生的 class 构造函数一样,而不是声明派生的 class 构造函数委托给基础 class 构造函数.在N4429的第一个版本中,有如下写法,保留了C++11的限制:
When a using-declaration declares that a class inherits constructors from a base class, the default constructor, copy constructor, and move constructor (if any) of the base class are excluded from the set of introduced declarations.
然而,在这篇论文的更新版本中,P0136R0,这个措辞不再存在,也没有给出原因的解释。该论文再次修订,然后合并到标准中。所以在 C++17 中,我看不到任何阻止上述代码编译的规则。
尽管如此,GCC and Clang both reject it。铿锵声说:
an inherited constructor is not a candidate for initialization from an expression of the same or derived type
但是,我在标准中找不到这样的内容。
此代码在 C++17 中是否格式错误?如果是,为什么?
A constructor inherited from class type
C
([class.inhctor.init]) that has a first parameter of type “reference to cv1P
” (including such a constructor instantiated from a template) is excluded from the set of candidate functions when constructing an object of type cv2D
if the argument list has exactly one argument andC
is reference-related toP
andP
is reference-related toD
.
参见CWG2356。
我认为 WG21 的规则是:
Base class copy and move constructors brought into a derived class via a using-declaration are not considered by overload resolution when constructing a derived class object.
如果 Base 的继承构造函数之一恰好具有与 Derived 的 copy/move 构造函数相匹配的签名,它不会阻止 Derived copy/move 构造函数的隐式生成。
请注意,using A::A;
指令 继承 所有构造函数,包括 copy/move 和 compiler-generated 默认构造函数 A
到派生class(s) 该指令出现的地方;以及 A 的所有构造函数, 除了 copy/move 和 compiler-generated 默认构造函数,在查找派生 class 的构造函数或形成集合时被考虑候选人。
struct B { B(); };
struct D : B { using B::B; };
D d{ B() }; // error: overload resolution found nothing. #1
D d{ D() }; // OK #2
默认的复制构造函数B::B(const B&)
被继承到D
但是这个构造函数不是候选函数。没有 using 指令,程序是 well-formed 因为这被认为是聚合初始化。此外 using-declaration 不会阻止编译器生成 D
的默认 copy/move 构造函数,这就是为什么 #2 可以。
现在为了抑制这个错误,我们应该明确地提供一个user-provided复制构造函数:
struct B{
B();
};
struct D : public B{
using B::B;
B(const B&);
};
D d{ B() }; // OK: overload resolution found constructor matches the argument-list.