16 Stimmen

Spezialisierungen von Klassenvorlagen mit gemeinsamer Funktionalität

Ich schreibe eine einfache mathematische Bibliothek mit einem Template-Vektortyp:

template<typename T, size_t N>
class Vector {
    public:
        Vector<T, N> &operator+=(Vector<T, N> const &other);
        // ... more operators, functions ...
};

Jetzt möchte ich etwas zusätzlich Funktionalität speziell für einige von ihnen. Sagen wir, ich möchte Funktionen x() et y() auf Vector<T, 2> um auf bestimmte Koordinaten zuzugreifen. Hierfür könnte ich eine partielle Spezialisierung erstellen:

template<typename T>
class Vector<T, 3> {
    public:
        Vector<T, 3> &operator+=(Vector<T, 3> const &other);
        // ... and again all the operators and functions ...
        T x() const;
        T y() const;
};

Aber jetzt wiederhole ich alles, was bereits in der generischen Vorlage vorhanden war.

Ich könnte auch die Vererbung nutzen. Umbenennung der generischen Vorlage in VectorBase Ich könnte das tun:

template<typename T, size_t N>
class Vector : public VectorBase<T, N> {
};

template<typename T>
class Vector<T, 3> : public VectorBase<T, 3> {
    public:
        T x() const;
        T y() const;
};

Das Problem ist nun aber, dass alle Operatoren auf VectorBase so kehren sie zurück VectorBase Instanzen. Diese können nicht zugewiesen werden Vector Variablen:

Vector<float, 3> v;
Vector<float, 3> w;
w = 5 * v; // error: no conversion from VectorBase<float, 3> to Vector<float, 3>

Ich könnte Vector einen impliziten Konvertierungskonstruktor, um dies zu ermöglichen:

template<typename T, size_t N>
class Vector : public VectorBase<T, N> {
    public:
        Vector(VectorBase<T, N> const &other);
};

Aber jetzt konvertiere ich von Vector à VectorBase und wieder zurück. Auch wenn die Typen im Speicher gleich sind und der Compiler all dies wegoptimieren könnte, fühlt es sich umständlich an, und ich mag es nicht wirklich, potenziellen Laufzeit-Overhead für etwas zu haben, das im Wesentlichen ein Kompilierzeitproblem ist.

Gibt es eine andere Möglichkeit, dieses Problem zu lösen?

4voto

James McNellis Punkte 337231

Hier ist etwas, das ich mir ausgedacht habe, als ich vor einiger Zeit mit C++0x-Funktionen spielte. Die einzige C++0x-Funktion, die hier verwendet wird, ist static_assert Sie könnten also Boost verwenden, um das zu ersetzen.

Im Grunde können wir eine statische Größenprüfungsfunktion verwenden, die lediglich überprüft, ob ein bestimmter Index kleiner als die Größe des Vektors ist. Wir verwenden eine statische Assert-Funktion, um einen Compilerfehler zu erzeugen, wenn der Index außerhalb der Grenzen liegt:

template <std::size_t Index> 
void size_check_lt() const 
{ 
    static_assert(Index < N, "the index is not within the range of the vector"); 
}

Dann können wir eine get() Methode, die einen Verweis auf das Element an einem bestimmten Index zurückgibt (eine const-Überladung wäre natürlich auch nützlich):

template <std::size_t Index> 
T& get()
{ 
    size_check_lt<Index>(); return data_[Index]; 
}

Dann können wir einfache Accessors wie diese schreiben:

T& x() { return get<0>(); }
T& y() { return get<1>(); }
T& z() { return get<2>(); }

Wenn der Vektor nur zwei Elemente hat, können Sie x und y verwenden, aber nicht z. Wenn der Vektor drei oder mehr Elemente hat, können Sie alle drei verwenden.

Am Ende habe ich dasselbe für Konstruktoren getan - ich habe Konstruktoren für Vektoren der Dimension zwei, drei und vier erstellt und eine size_check_eq die es erlaubten, sie nur für Vektoren der Dimension zwei, drei bzw. vier zu instanziieren. Ich kann versuchen, den vollständigen Code zu posten, wenn ich heute Abend nach Hause komme, falls jemand daran interessiert ist.

Ich habe das Projekt auf halbem Weg abgebrochen, also könnte es ein großes Problem geben, das ich nicht hatte... zumindest ist es eine Option, die man in Betracht ziehen kann.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X