2016-04-06 13 views
9

Ich habe die folgende nicht-Typen Vorlage:Überlastung Kopie Zuweisungsoperator für ein Mitglied struct eine nicht-Typ Template-Struktur

template<size_t MAX_SIZE> 
struct Path{ 
    struct Point{ 
     float x; 
     float y; 
     } 
    }; 
    Point segment[MAX_SIZE]; 
}; 

Wenn ich jetzt zwei verschiedene Pfade erklären, kann ich nicht Elemente der verschiedenen Segmente zuzuweisen zueinander, da die Strukturen die gleiche Struktur aufweisen, sind aber von einem anderen Typ:

Path<10> path_a ; 
Path<30> path_b ; 
path_a.segment[0].x = 1; 
path_a.segment[0].y = 2; 
path_b.segment[0] = path_a.segment[0]; // <- error C2679 in Visual Studio) 

natürlich, wenn ich die Definition von Point-and-Pfad trennen, würde die Zuordnung arbeiten:

struct Point{ 
     float x; 
     float y; 
     }; 

template<size_t MAX_SIZE> 
struct Path{ 
    Point segment[MAX_SIZE]; 
}; 

Aber das ist nicht was ich will (das ist nur ein MWE), also habe ich mich gefragt, wie ich den Kopierzuweisungsoperator überladen kann, damit es funktioniert. Ich habe verschiedene Varianten ausprobiert, zum Beispiel:

template<size_t MAX_SIZE> 
struct Path{ 
    struct Point{ 
     float x; 
     float y; 
     template<size_t OTHER_SIZE> 
     Point & operator = (const typename Path<OTHER_SIZE>::Point & that) 
     { 
      x = that.x; 
      y = that.y; 
      return *this; 
     } 
    }; 
    Point segment[MAX_SIZE]; 
}; 

aber ich bekomme immer den gleichen Fehler. Meine Frage ist also: Ist es möglich, overload = in einer Weise, die eine Zuordnung der folgenden Form ermöglicht, ohne das Layout meiner Strukturen zu ändern?

path_b.segment[0] = path_a.segment[0]; 
+1

nur sicherstellen, dass Sie nicht X-Y'ing dies sind, können Sie auf erarbeiten * warum * jeder Punkt den Weg muss ein eigener Typ sein, aber immer noch einander zuweisbar? –

+0

@MarkB, das ist irrelvant Frage. Die Frage ist eigenständig gültig. Das Zuweisen innerer Strukturen von verschiedenen äußeren Vorlagen ist eine eigenständige Sache. – SergeyA

+0

@MarkB: Der Hauptgrund ist, dass ich ein bisschen stur bin und wirklich wissen wollte, ob es einen Weg gibt, es zum Laufen zu bringen. Außerdem ist möglicherweise eine Problemumgehung für das hier vorgestellte einfache Beispiel möglich, aber nicht im allgemeinen Fall, da es beispielsweise mehrere Änderungen in einer vorhandenen Codebasis erfordern kann. – magnetometer

Antwort

5

Ja, solche Einrichtung möglich ist. Im Kern müssen Sie einen Zuweisungsoperator Vorlage, die alle Arten annehmen:

template<class T> 
Point & operator = (const T & that) 

Als Basislösung, würde dies ausreichen. Es wird jetzt mit allen Typen arbeiten, die Mitglieder x und y von kompatiblen Typen haben und eine (normalerweise) hässliche Fehlermeldung für Typen erzeugen, die dies nicht tun.

Wenn das gut genug für Sie ist, sind wir fertig.

Wenn Sie andere Überladungen des Zuweisungsoperators haben, möchten Sie wahrscheinlich die Vorlage selektiv deaktivieren. Dazu werden Sie die Point Klassen Instrument benötigen und benutzen SFINAE:

template<size_t MAX_SIZE> 
struct Path{ 
    struct Point{ 
     float x; 
     float y; 
     struct EnableAssignment {}; 
    }; 
    Point segment[MAX_SIZE]; 
}; 

Die Instrumentierung dann wie folgt verwendet:

template<class T, class U = typename T::EnableAssignment> 
Point & operator = (const T & that) 

[Simplified live example]


Der obige Code verwendet ein Standardvorlagenargument in einer Funktionsvorlage, die nur in C++ 11 eingeführt wurde.Davor, würden Sie SFINAE auf andere Weise zu berufen haben:

template <class L, class R> 
struct SfinaeThenRight 
{ 
    typedef R type; 
}; 

template <class T> 
typename SfinaeThenRight<typename T::EnableAssignment, Point&>::type operator = (const T & that) 

[Simplified C++98 live example]

+0

Ja, das ist der bessere Ansatz. Das ist, was ich gesucht habe, aber Sie haben mich dazu geschlagen. Fixiere einfach deinen Code, um ihn kompilierbar zu machen. – SergeyA

+0

@SergeyA Was genau ist falsch daran? – Angew

+0

Versuchen Sie es einfach zu kompilieren. Ihre Signatur für Operator = ist nicht korrekt. Punkt ist kein Typ, den man so benutzen kann, es ist ein innerer Typ von Pfad (oder setze ihn in die Definition von Point). – SergeyA

2
template<size_t OTHER_SIZE> 
Point & operator = (const typename Path<OTHER_SIZE>::Point & that) 

wird nicht funktionieren, weil das Template-Argument OTHER_SIZE auf der äußeren Struktur nicht abgeleitet werden kann. Sie können einfach:

template<typename T> 
Point & operator = (const T & that) 
{ 
    x = that.x; 
    y = that.y; 
    return *this; 
} 

Beachten Sie, dass, wenn etwas ohne Mitglied x und y weitergegeben werden Sie einen Compiler-Fehler erhalten, die für diesen Fall ausreichend sein sollte.

LIVE

+0

Dies ist eine schreckliche Lösung. Es wird gerne ** alles ** essen, das x und y in ihnen hat, und einen möglichen logischen Fehler im Programm maskieren. – SergeyA

+0

@SergeyA Es sollte für den Fall von OP reichen. Wenn etwas Inkompatibles als rhs übergeben wird, erhalten wir einen Compilerfehler. Unnötige Komplexität könnte auch schaden. – songyuanyao

+0

Das Problem ist nicht mit etwas, das nicht x oder y darauf hat. Das Problem ist mit etwas, das tut, hat aber keinerlei Beziehung zu Pointer. – SergeyA