转发构造函数调用基类的复制构造函数2次

Forwarding constructors calls 2 times copy constructor of base class

本文关键字:复制 构造函数 2次 基类 函数调用 转发      更新时间:2023-10-16

以下代码将构造函数从基类转发到派生类。

为什么要调用2个复制构造函数?背景中发生了什么?

用g++编译。

#include <iostream>
using namespace std;
struct A {
A() { cout << "A" << endl; }
A(const A&) { cout << "A(const A&)" << endl; }
template<typename T> A(T a); // Needed to compile :-O
};
template<typename T>
struct C : public T { using T::T; };
int main()
{
A a;
C<A> ca(a);
//C<A> caa(ca);
return 0;
}

输出为:

A
A(const A&)
A(const A&)

通过在A中定义构造函数模板,C将获得一个具有类似签名的构造函数模板。它的定义类似于:

template<typename T>
struct C : public T
{
//using T::T;
C() = default;
C(C const&) = default;
template<typename U> C(U a) : T( std::forward<U>(a) ) {}
};

这现在调用A的复制构造函数两次:一次用于按值获取参数。第二个调用来自T( std::forward<U>(a) )调用A的复制ctor。这让我很惊讶,因为你会期望一个继承的ctor调用它所继承的基类的确切ctor。但事实并非如此,重载解析选择的不是A的ctor模板,而是纯拷贝的ctorA(A const&)(见下文)。


有趣的是,它不太关心A中的构造函数模板做什么,只需要声明它。这就是为什么在OP中,定义可能会丢失;它也可以被删除(这可能是一个缺陷?)。

只需要在初始化CCD_ 10的过载解析期间选择CCD_。这里的情况是这样的:参数是A类型的右值,它可以直接绑定到const A&引用,这是a的副本ctor所要求的。由于引用绑定是直接的,并且不派生到基转换,因此副本ctor列为精确匹配。A中的ctor模板也被列为"精确匹配",但由于重载集中有一个级别相同的模板和非模板函数,因此首选非模板函数(复制ctorA(A const&))。

A::A(const A&)的一个调用是C<A>的基类构造函数。

另一个用于复制pass-by-value参数。