2010-10-25 20 views
11

Ich habe einige Probleme beim Definieren einiger Operatorüberladungen für Vorlagenklassen. Nehmen wir diese hypothetische Klasse zum Beispiel.Operator überladen auf Klassenvorlagen

template <class T> 
class MyClass { 
    // ... 
}; 
  • Operator + =

    // In MyClass.h 
    MyClass<T>& operator+=(const MyClass<T>& classObj); 
    
    
    // In MyClass.cpp 
    template <class T> 
    MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) { 
        // ... 
        return *this; 
    } 
    

    Ergebnisse in dieser Compiler-Fehler:

    no match for 'operator+=' in 'classObj2 += classObj1' 
    
  • Betreiber < <

    // In MyClass.h 
    friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj); 
    
    
    // In MyClass.cpp 
    template <class T> 
    std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj) { 
        // ... 
        return out; 
    } 
    

    Ergebnisse in dieser Compiler-Warnung:

    friend declaration 'std::ostream& operator<<(std::ostream&, const MyClass<T>&)' declares a non-template function 
    

Was mache ich hier falsch?

+0

können Sie einige echte Code posten, die kompilieren fehlschlägt? – Naveen

+0

@Naveen: Sie können eine gezippte Version unter http://www.box.net/shared/v23rj2f8e7 – Pieter

Antwort

7
// In MyClass.h 
MyClass<T>& operator+=(const MyClass<T>& classObj); 


// In MyClass.cpp 
template <class T> 
MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) { 
    // ... 
    return *this; 
} 

Dies ist ungültig für Vorlagen machen. Der vollständige Quellcode des Operators muss sich in allen Übersetzungseinheiten befinden, in denen er verwendet wird. Dies bedeutet normalerweise, dass der Code in der Kopfzeile inline ist.

Bearbeiten: Technisch, nach dem Standard, ist es möglich, Vorlagen zu exportieren, jedoch nur sehr wenige Compiler unterstützen es. Darüber hinaus können Sie das obige auch tun, wenn die Vorlage explizit in MyClass.cpp für alle Typen, die T sind, instanziert wird, aber in der Realität, die normalerweise dem Punkt einer Vorlage widerspricht.

Mehr bearbeiten: Ich lese durch Ihren Code, und es braucht etwas Arbeit, zum Beispiel Überladung Operator []. Außerdem würde ich normalerweise die Dimensionen zu einem Teil der Template-Parameter machen, so dass der Fehler + oder + = bei der Kompilierung abgefangen wird und der Typ sinnvoll stapelweise zugewiesen wird. Ihre Ausnahmeklasse muss auch von std :: exception abgeleitet werden. Keiner von diesen beinhaltet Kompilierungsfehler, sie sind einfach kein großartiger Code.

0

Sie müssen angeben, dass der Freund eine Funktionsschablone ist:

MyClass<T>& operator+=<>(const MyClass<T>& classObj); 

Siehe this C++ FAQ Lite Antwort für Details.

12

Sie müssen das sagen, folgende (da Sie eine ganze Vorlage statt nur eine Spezialisierung davon anfreunden, wobei in diesem Fall brauchen Sie nur würde eine <> nach dem operator<< hinzugefügt werden):

template<typename T> 
friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj); 

Eigentlich muss es nicht als Freund deklariert werden, wenn es nicht auf private oder geschützte Mitglieder zugreift. Da Sie nur eine Warnung bekommen, scheint es, Ihre Erklärung der Freundschaft ist keine gute Idee. Wenn Sie einfach eine Spezialisierung davon als Freund deklarieren möchten, können Sie das wie unten gezeigt tun, mit einer Vorwärtsdeklaration der Vorlage vor Ihrer Klasse, so dass operator<< als Vorlage erkannt wird.

// before class definition ... 
template <class T> 
class MyClass; 

// note that this "T" is unrelated to the T of MyClass ! 
template<typename T> 
std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj); 

// in class definition ... 
friend std::ostream& operator<< <>(std::ostream& out, const MyClass<T>& classObj); 

Sowohl die oben und auf diese Weise erklären Spezialisierungen es als Freunde, aber die erste erklärt alle Spezialisierungen als Freunde, während die zweite nur die Spezialisierung der operator<< als Freund, dessen erklärt T gleich der T der Klasse, die Freundschaft gewährt.

Und im anderen Fall sieht Ihre Erklärung OK, aber beachten Sie, dass Sie nicht += ein MyClass<T> kann ein MyClass<U> wenn T und U andere Art sind mit dieser Erklärung (es sei denn Sie eine implizite Konvertierung zwischen diesen Typen haben). Sie können Ihre += Mitglied Vorlage

// In MyClass.h 
template<typename U> 
MyClass<T>& operator+=(const MyClass<U>& classObj); 


// In MyClass.cpp 
template <class T> template<typename U> 
MyClass<T>& MyClass<T>::operator+=(const MyClass<U>& classObj) { 
    // ... 
    return *this; 
} 
2

http://www.parashift.com/c++-faq-lite/template-friends.html

Das half mir mit dem exakt gleichen Problem.

Soln:

  1. Weiterleiten, um die Friend-Funktion vor der Definition der Klasse selbst erklären. Für die Ex:

    template<typename T> class MyClass; // pre-declare the template class itself 
        template<typename T> std::ostream& operator<< (std::ostream& o, const MyClass <T>& x); 
    
  2. Erklären Sie Ihre Freund-Funktion in der Klasse mit "<>", um die Funktionsnamen angehängt.

    friend std::ostream& operator<< <> (std::ostream& o, const Foo<T>& x); 
    
+0

Link führt zu Timeout. – TobiMcNamobi

-1

Auf diese Weise funktioniert:

class A 
{ 
    struct Wrap 
    { 
     A& a; 
     Wrap(A& aa) aa(a) {} 
     operator int() { return a.value; } 
     operator std::string() { stringstream ss; ss << a.value; return ss.str(); } 
    } 
    Wrap operator*() { return Wrap(*this); } 
};