2016-07-28 139 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'是兩個不同的類,它們沒有任何關係。 –