2016-07-28 134 views
1

想象一下下面的例子:模板化拷贝构造

#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初始化Ç类型来自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这些2个错误:

错误C2679二进制'=':找不到操作符,它需要一个类型为'const std :: vector :: Element,std :: allocator < _Ty >>'的右侧操作数'(或者没有可接受的转换)

错误C2664 'A :: A(A & &)':无法从 '基地' 转换参数1 'const的一个&'

据我了解,性病::向量已经有一个赋值运算符实现,该赋值运算符应该在运算符的右侧创建向量的深层副本。

那么我做错了什么,我需要做些什么才能使它工作?

+0

您可能需要为您的Base类添加一个'virtual Base * clone()const = 0;'并在派生类中重写它以执行实际的克隆,然后调用它来复制'p'。 – evan

回答

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,它是相同类型的向量,并且它们可以相互分配。

+0

+1开场重点。当我进入模板元编程领域时,了解到某些类别和类别是完全不同的类型花了一些时间。 – Kahler

+0

感谢您的回复,移动Element类工作。令我惊讶的是,尽管Element在两个载体中都完全相同,但2种载体被认为是不同的类型。 –

+0

'class A {class Element {int x; }}; class B {class Element {int x; }}'''A :: Element'和'B :: Element'是两个不同的类,它们没有任何关系。 –