Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 转发构造函数调用基类的复制构造函数2次_C++_C++11_Constructor - Fatal编程技术网

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

C++ 转发构造函数调用基类的复制构造函数2次,c++,c++11,constructor,C++,C++11,Constructor,下面的代码将构造函数从基类转发到派生类 为什么要调用2个复制构造函数?背景是什么 用g++编译 #include <iostream> using namespace std; struct A { A() { cout << "A" << endl; } A(const A&) { cout << "A(const A&)" << endl; } template<typename T&

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

为什么要调用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&)
的一个调用是
C
的基类构造函数


调用另一个来复制pass by value参数。

通过在
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) ) {}
};
模板
结构C:公共T
{
//使用T::T;
C()=默认值;
C(C const&)=默认值;
模板C(ua):T(std::forward(a)){
};
现在调用
A
的复制构造函数两次:一次用于按值获取参数。第二次调用的结果是调用
a的复制构造函数
T(std::forward(a))
。这让我感到惊讶,因为您希望继承的构造函数调用它所继承的基类的确切构造函数。但事实并非如此,重载解析选择的不是
A
的ctor模板,而是纯拷贝ctor
A(常数&)
(见下文)


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


只有在初始化
T(std::forward(A))
的重载解析期间,才必须选择
A
的复制选择器。这里的情况是这样的:参数是一个类型为
A
的右值,它可以直接绑定到
常量A&
引用,这是A的复制构造函数所要求的。由于引用绑定是直接绑定的,并且不进行从基到基的转换,因此复制构造函数的排名是完全匹配的。
A
中的ctor模板也被列为精确匹配,但由于重载集中有一个具有相同级别的模板和非模板函数,因此首选非模板函数(复制ctor
A(常数&)
)。

请发布实际代码。你发布的内容没有编译:@JimBuck好的,我添加了一个模板构造函数,它会编译。。。出于同样的原因,根据12.9/8:“表达式列表中的每个表达式的形式为
static_cast(p)
,其中
p
是相应构造函数参数的名称,
T
p
的声明类型。”我认为应该是
T(static_cast(a))
,因此,它应该更喜欢
A
的移动构造函数而不是复制构造函数(如果有)。@Casey是的,但这正是
forward
所做的,我认为
forward
可能更常见/更容易理解。如何防止双重调用?@KarolyHorvath,这取决于上下文。通常,您可以编写具有完美转发的构造函数,因此可以使用
模板a(T&&)
A
中,但这太贪婪了,需要受SFINAE的限制。另一种方法是在
C
中定义额外的系数。如果您为该示例提供一些上下文,也许我们可以找到一个合适的解决方案。@DyP对
A(const&)
的解释比
A&&
参数的模板构造函数更好。
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) ) {}
};