以下代码将构造函数从base转发为派生类。
为什么要复制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&)
答案 0 :(得分:6)
对A::A(const A&)
的一次调用是C<A>
的基类构造函数。
调用另一个来复制pass-by-value参数。
答案 1 :(得分:6)
通过在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。但情况并非如此,重载决策不会选择A
的ctor模板,而是选择普通副本A(A const&)
(见下文)。
有趣的是,它并不关心A
中构造函数模板的作用,只需要声明它。这就是为什么在OP中,定义可能会丢失;它也可以删除(这可能是一个缺陷?)。
只有在初始化A
的重载解析期间才需要选择T( std::forward<U>(a) )
的副本。这是这种情况:参数是类型A
的右值,它可以直接绑定到const A&
引用,这是A的copy-ctor所要求的。因为引用绑定是直接的和w / o派生到基础的转换,复制者排名为完全匹配。 A
中的ctor模板也被排列为精确匹配,但由于在重载集中存在具有相同排名的模板和非模板函数,因此首选非模板函数(复制程序) A(A const&)
)。