模板化复制构造函数

时间:2016-07-28 01:56:10

标签: c++ templates constructor

想象一下以下示例:

#include <iostream>
#include <vector>

struct Base
{
    virtual void foo() = 0;
};

struct A : public Base
{
    void foo() override {};
};

struct B : public Base
{
    void foo() override {};
};

template <typename T>
struct C
{
    struct Element
    {
        int x, y, z;

        bool operator==(const Element& e)
        {
            if (x != e.x) return false;
            if (y != e.y) return false;
            if (z != e.z) return false;
            return true;
        }
    };

    Base* p;
    std::vector<Element> v;

    C()
    {
        p = new T();
    }

    void add(int x, int y, int z)
    {
        Element e;
        e.x = x;
        e.y = y;
        e.z = z;
        v.push_back(e);
    }

    void remove(int x, int y, int z)
    {
        Element e;
        e.x = x;
        e.y = y;
        e.z = z;
        std::vector<Element>::iterator it = std::find(v.begin(), v.end(), e);
        if (p != v.end()) v.erase(p);
    }

    void print()
    {
        for (Element e : v) std::cout << e.x << " " << e.y << " " << e.z << std::endl;
    }
};

int main()
{
    C<A> a;

    a.add(1, 2, 3);
    a.add(4, 5, 6);
    a.add(7, 8, 9);

    a.remove(4, 5, 6);

    a.print();

    return 0;
}

现在让我们在C中添加一个拷贝构造函数,这样我们就可以用另一个保存另一个数据类型的C来初始化C(只要数据类型派生自Base)。目标是使这成为可能:

int main()
{
    C<A> a;

    a.add(1, 2, 3);
    a.add(4, 5, 6);
    a.add(7, 8, 9);

    a.remove(4, 5, 6);

    a.print();

    C<B> b(a); // <----- This should be possible.

    return 0;
}

我试图像这样解决它:

template <typename U>
C(const C<U>& c)
{
    p = new U(*c.p);
    v = c.v;
}

但是我从Visual Studio中得到了这两个错误:

  

错误C2679二进制'=':找不到运算符,它接受类型为'const std :: vector :: Element,std :: allocator&lt; _Ty&gt;&gt;'的右侧操作数(或者没有可接受的转换)

     

错误C2664'A :: A(A&amp;&amp;)':无法将参数1从'Base'转换为'const A&amp;'

根据我的理解,std :: vector已经实现了一个赋值操作符,它应该在操作符的右侧创建一个向量的深层副本。

那么我做错了什么,我需要做些什么才能让它发挥作用?

1 个答案:

答案 0 :(得分:2)

v = c.v;

这是两种完全不同的类型。

vstd::vector<C<T>::Element>

c.vstd::vector<C<U>::Element>

鉴于不同的TU类型,C<T>C<U>是完全不同的类型,彼此无关。

C<T>::ElementC<U>::Element也是完全不同的类型。每个std::vector也是如此。

C<T>::ElementC<U>::Element可能具有相同的类名。他们可能拥有完全相同的班级成员。但它们是两种独立的类型,因为class Aclass B不同,彼此之间也是不同的。 问题不在于模板拷贝构造函数本身。问题是拷贝构造函数试图为彼此分配一种类型。

您需要做的是删除内部类Element。它不依赖于模板参数。使其成为一个独立的顶级课程。然后,C<T>C<U>都会有一个类成员v,它是相同类型的向量,并且可以相互分配。