2016-07-28 5 views
1

Stellen Sie sich das folgende Beispiel:Templated Copy-Konstruktor

#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; 
} 

Lassen Sie uns jetzt einen Copy-Konstruktor in C hinzufügen, so dass wir C mit einem anderen C, die einen anderen Datentyp hält (solange die Daten- initialisieren Typ stammt von Base). Das Ziel ist, dies möglich zu machen:

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; 
} 

Ich habe versucht, es so zu lösen:

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

Aber ich bekomme diese 2 Fehler von Visual Studio:

Fehler C2679 binary '=': kein Operator gefunden, der einen rechten Operanden vom Typ 'const std :: vector :: Element, std :: allocator < _Ty >>' (oder es gibt keine akzeptable Konvertierung)

Fehler C2664 'A :: A (A & &)': nicht Argument 1 von 'Base' umwandeln kann zu 'const A &'

Von dem, was ich verstanden habe, std :: vector bereits hat Zuweisungsoperator implementiert, der eine tiefe Kopie des Vektors auf der rechten Seite des Operators machen sollte.

Was mache ich also falsch und was muss ich tun, damit es funktioniert?

+0

Sie müssen wahrscheinlich eine 'virtuelle Basis * clone() const = 0;' zu Ihrer Basisklasse hinzufügen und diese in den abgeleiteten Klassen überschreiben, um das eigentliche Klonen durchzuführen, und dann zum Kopieren von 'p' aufrufen. – evan

Antwort

2
v = c.v; 

Dies sind zwei völlig verschiedene Arten.

v ist std::vector<C<T>::Element>.

c.v ist std::vector<C<U>::Element>.

Gegeben verschiedene T und U Typen, C<T> und C<U> sind völlig verschiedene Typen, die keine Beziehung zueinander haben.

C<T>::Element und C<U>::Element sind auch völlig verschiedene Arten. So ist ein std::vector von jedem auch.

C<T>::Element und C<U>::Element können denselben Klassennamen haben. Sie können die gleichen genauen Klassenmitglieder haben. Aber sie sind zwei unabhängige Typen, so unterschiedlich wie class A unterscheidet sich von class B. Das Problem ist nicht der Template-Copy-Konstruktor selbst. Das Problem besteht darin, dass der Kopierkonstruktor versucht, sich gegenseitig einen Typ zuzuweisen.

Was Sie tun müssen, ist die innere Klasse Element zu entfernen. Es hängt nicht von einem Vorlagenparameter ab. Machen Sie es zu einer unabhängigen Top-Level-Klasse. Dann haben sowohl C<T> als auch C<U> einen Klassenmember v, der ein Vektor des gleichen Typs ist, und sie können einander zugeordnet werden.

+0

+1 für den Anfangsschwerpunkt.Als ich den Bereich der Metaprogrammierung von Templates betrat, brauchte es einige Zeit, zu verstehen, dass someClass und someClass völlig unterschiedliche Typen sind. – Kahler

+0

Vielen Dank für Ihre Antwort, das Verschieben der Element-Klasse hat funktioniert. Was mich überraschte, war, dass die 2 Vektoren als unterschiedliche Typen betrachtet wurden, obwohl Element in beiden Vektoren genau gleich war. –

+0

'Klasse A {Klassenelement {int x; }}; Klasse B {Klassenelement {int x; }} '-' A :: Element' und 'B :: Element' sind zwei verschiedene Klassen, die nichts miteinander zu tun haben. –

Verwandte Themen