2017-01-17 1 views
0

Ich möchte eine generische (mathematische) Vektorklasse schreiben, die swizzling unterstützt, ich fand zwei Referenzen dafür (CxxSwizzle und Performance Optimal Vector Swizzling in C++ ²). Ich mag den geradlinigen Stil der Implementierung der Swizzling als Subclassed Union-Mitglieder in ², aber ich möchte etwas über die Variadic-Vorlage lernen, wie es in CxxSwizzle getan wird.C++ Variadic Vektoroperator Implementierung

Hier ist ein kleiner Ausschnitt, dass ich weiß nicht, wie zu implementieren (die Templat-sqrt Funktion ist hier in der Länge/Größe für benutzerdefinierte Typen zu implementieren):

#include <cmath> 
#include <cstdint> 
#include <type_traits> 

template<class T> 
using vec_sqrt_function = typename std::add_pointer<T(const T)>::type; 

template<class VEC_TYPE, class T, vec_sqrt_function<T> SQRT_FN, std::int32_t... X> 
struct vec_impl 
{ 
    template<class VEC_TYPE2, class T2, vec_sqrt_function<T2> SQRT_FN2, std::int32_t... X2> 
    VEC_TYPE& operator +=(const vec<VEC_TYPE2, T2, SQRT_FN2, ...X2>& RHS) 
    { 
     // ??? 
     return *this; 
    } 
}; 

struct vec2 : public vec_impl<vec2, float, std::sqrt, 0, 1> 
{ 
    union 
    { 
     float data[2]; 

     vec_impl<vec2, float, std::sqrt, 0> x; 
     vec_impl<vec2, float, std::sqrt, 1> y; 

     vec_impl<vec2, float, std::sqrt, 0, 0> xx; 
     vec_impl<vec2, float, std::sqrt, 0, 1> xy; 
     vec_impl<vec2, float, std::sqrt, 1, 0> yx; 
     vec_impl<vec2, float, std::sqrt, 1, 1> yy; 
    }; 
}; 

Von dem, was ich aus verstehen Mehrere Tutorials zu lesen ist, dass ich die vec_impl mit einer Vorlage des Formulars template<..., std::int32_t X, std::int32_t... REST> spezialisieren muss, aber da ich die gleiche variadic Vorlage für den += Operator verwende, muss ich den Operator += in der gleichen Weise spezialisieren, für eine Gesamtheit, die das selbe implementiert Funktion 4 mal?

Gibt es eine einfachere Möglichkeit, dies zu implementieren (ich habe nicht ganz verstanden, wie CxxSwizzle Arithmetik über alle Vorlagen implementiert)?

bearbeiten: Zur weiteren Klärung, was ich wissen will, ist, wie syntaktisch über variadische Vorlagen statt separate Klassen folgendes zu implementieren:

template<class VEC_TYPE, class T, std::int32_t X1> 
struct vec1_swizzle 
{ 
    template<class VEC_TYPE2, class T2, std::int32_t Y1> 
    VEC_TYPE& operator += (const vec1_swizzle<VEC_TYPE2, T2, Y1>& RHS) 
    { 
     ((T*)this)[X1] += ((T*)&RHS)[Y1]; 
     return *this; 
    } 
} 

struct vec1f : public vec1_swizzle<vec1f, float, 0> 
{ 
    union 
    { 
     float data[1]; 
     vec1_swizzle<vec1f, float, 0> x; 
     vec2_swizzle<vec2f, float, 0, 0> xx; 
     // same for 3 & 4 
    } 
} 


template<class VEC_TYPE, class T, std::int32_t X1, std::int32_t X2> 
struct vec2_swizzle 
{ 
    template<class VEC_TYPE2, class T2, std::int32_t Y1, std::int32_t Y2> 
    VEC_TYPE& operator += (const vec1_swizzle<VEC_TYPE2, T2, Y1, Y2>& RHS) 
    { 
     ((T*)this)[X1] += ((T*)&RHS)[Y1]; 
     ((T*)this)[X2] += ((T*)&RHS)[Y2]; 
     return *this; 
    } 
} 

struct vec2f : public vec2_swizzle<vec2f, float, 0, 1> 
{ 
    union 
    { 
     float data[2]; 
     vec1_swizzle<vec1f, float, 0> x; 
     vec1_swizzle<vec1f, float, 1> y; 
     vec2_swizzle<vec2f, float, 0, 0> xx; 
     vec2_swizzle<vec2f, float, 0, 1> xy; 
     vec2_swizzle<vec2f, float, 1, 0> yx; 
     vec2_swizzle<vec2f, float, 1, 1> yy; 
     // same for 3 & 4 
    } 
} 

Ich möchte die vec#_swizzle Klasse von Templating „generify“ die Anzahl der bestandenen Indizes.

+0

zwei Vektoren nur Hinzufügen Sinn macht wenn sie gleich lang sind, nein? – AndyG

+0

Das ist eine sehr seltsame Art zu versuchen, 'vec2' zu implementieren. Sind Sie sicher, dass Sie verstehen, wie eine Gewerkschaft funktioniert? Die harte Wahrheit ist, dass eine Menge davon für Ihr Verständnis der Sprache zu diesem Zeitpunkt etwas zu kompliziert erscheint. Beginnen Sie klein, mit dem Lesen über Polymorphismus und dann Vektoren und dann C++ 03-Stilvorlagen. Und dann variadische Templates, statische Assertion, Template-Spezialisierung, partielle Template-Spezialisierung (speziell bezüglich Member-Funktionen). Und was ist eine Vereinigung? (boost :: variant oder std :: variant sind auch gute reads). – AndyG

+0

@AndyG Ich glaube, du hast meine Frage falsch verstanden. Ich weiß, wie ich über separate Template-Klassen implementieren kann, was ich möchte. Wie würde ich das in einer Klasse implementieren, wenn das Sinn macht (es ist eher eine Syntaxfrage als eine Logikfrage)? Ich habe die Frage bearbeitet, um hoffentlich mehr zu sein klar darüber, was ich wissen will. – prydain

Antwort

2

nicht sicher, was Sie mit der Gewerkschaft Teil wollen, aber im Anschluss könnte Ihnen helfen:

template<class VEC_TYPE, class T1, std::int32_t ... X1s> 
struct vec_swizzle 
{ 
    template<class VEC_TYPE2, class T2, std::int32_t ... Y1s> 
    VEC_TYPE& operator += (const vec1_swizzle<VEC_TYPE2, T2, Y1s...>& RHS) 
    { 
     static_assert(sizeof...(X1s) == sizeof...(Y1s), 
         "type mismatches"); // Better error message 

     // The "Loop" 
     const int dummy[] = { 0, ((((T1*)this)[X1s] += ((T2*)&RHS)[Y1s]), 0)...}; 
     static_cast<void>(dummy); // Avoid warning for unused variable 
     return *this; 
    } 
}; 

Oder in C++ 17, mit klappbarer Ausdruck:

template<class VEC_TYPE, class T1, std::int32_t ... X1s> 
struct vec_swizzle 
{ 
    template<class VEC_TYPE2, class T2, std::int32_t ... Y1s> 
    VEC_TYPE& operator += (const vec1_swizzle<VEC_TYPE2, T2, Y1s...>& RHS) 
    { 
     static_assert(sizeof...(X1s) == sizeof...(Y1s), 
         "type mismatches"); // Better error message 

     // The "Loop" 
     ((((T1*)this)[X1s] += ((T2*)&RHS)[Y1s]), ...); 
     return *this; 
    } 
}; 
+0

Funktioniert gut! Ist dies der "idiomatische" Weg, variable Schablonen auszupacken, fühlt es sich ein bisschen hackisch an (nicht, dass die Verwendung von Unionen für verschiedene Speichermuster nicht möglich war)? – prydain

+0

@prydain, C++ 17 fache Ausdrücke würden diese zwei Zeilen vereinfachen '((((T1 *) dies) [X1s] + = ((T2 *) & RHS) [Y1s]), ...);' für Nun können Sie jedoch ein wiederverwendbares Dienstprogramm definieren: 'struct slurp {Vorlage explizite slurp (Args && ...) {}}; 'und benutze es:' slurp {(((T1 *) this) [X1s] + = ((T2 *) & RHS) [Y1s]) ...}; '. –