2016-12-19 4 views
3

Motivation - in abstrakte Mathematik können wir 3-dimensionale Kreuzprodukt zu n Dimensionen verallgemeinern, unter der Annahme, dass für zwei Vektoren v,w der Dimension n, ihr Kreuzprodukt Dimension haben wird n(n-1)/2. Ich überspringe die Idee der Differentialformen und möchte diese Idee in die Sprache der Templates in der C++ - Bibliothek einbringen. Ich hatte diese Idee:C++: Benutzerdefinierte Rückgabewert für verschiedene Arten von Template-Funktion (Methode)

auto Cross(const Vec<dim, float_t> &rhs) { 
    if (dim == 0)return; 
    if (dim == 1)return (float_t)0; 
    if (dim == 2)return Values[0] * rhs.Values[1] - Values[1] * rhs.Values[0]; 
    if (dim == 3)return Vec<dim, float_t>(
     Values[1] * rhs.Values[2] - Values[2] * rhs.Values[1], 
     Values[2] * rhs.Values[0] - Values[0] * rhs.Values[2], 
     Values[0] * rhs.Values[1] - Values[1] * rhs.Values[0]); 

    //... 
} 

aber leider auto Spezifizierer nicht erlaubt für verschiedene Rückgabetypen. Ich könnte natürlich Chaos mit Vorprozessors, aber ich glaube, dass es mehr cleverer Weg, es zu tun, so etwas wie:

Vec<dim*(dim-1)/2,float_t> Cross(const Vec<dim,float_t> &rhs); 

(mit void als Sonderfall für nulldimensionalen Punkt und nur float_t für eindimensionale Punkt). Wie kann man das auf intelligente Weise lösen?

+0

Schreiben Sie überbelastete/Spezialisierungsfunktionen, die entweder einen 'const Vec <0, float_t> &' -Parameter oder einen 'const Vec &' -Parameter, etc ... Jeder überladen/specialized function wird einen geeigneten Rückgabetyp dafür haben. –

+1

In C++ 17 können Sie dies mit 'if conexpr' machen, aber bis das verfügbar ist, müssen Sie Spezialisierungen wie in @ alfCs Antwort verwenden. –

Antwort

1

Eine Möglichkeit, dies zu implementieren, ist durch Spezialisierungen. Ohne Spezialisierung wäre es sehr schwierig, einen wirklich generischen Template-Algorithmus zu implementieren (an dem ich interessiert wäre).

Wenn Sie Spezialisierungen verwenden, können Sie in den meisten Fällen nicht verwenden, die Rückgabetypen müssen explizit sein. Dies sollte das tun, was Sie wollen:

#include<cassert> 
#include<array> 

using std::array; 

template<std::size_t Dim> 
array<double, Dim*(Dim-1)/2> 
Cross(array<double, Dim> const&, array<double, Dim> const&); 

template<> array<double, 0> Cross(
    array<double, 1> const&, array<double, 1> const& v2 
){return {};} 

template<> array<double, 1> Cross(
    array<double, 2> const& v1, array<double, 2> const& v2 
){return {{v1[0] * v2[1] - v1[1] * v2[0]}};} 

template<> array<double, 3> Cross(
    array<double, 3> const& v1, array<double, 3> const& v2 
){ 
    return {{ 
     v1[1] * v2[2] - v1[2] * v2[1], 
     v1[2] * v2[0] - v1[0] * v2[2], 
     v1[0] * v2[1] - v1[1] * v2[0] 
    }}; 
} 

int main(){ 
    array<double, 1> v1{{1.}}; 
    array<double, 2> v2{{1.,2.}}; 
    array<double, 3> v3{{1.,2., 3.}}; 

    assert((Cross(v1, v1) == array<double, 0>{})); 
    assert((Cross(v2, v2)[0] == 0.)); 
    assert((Cross(v3, v3)[0] == 0.)); 
} 

An diesem Punkt, wenn Sie wissen, Sie gehen mit (insgesamt) Spezialisierungen arbeiten (wie oben), gibt es wenig Unterschied zwischen diesem und separaten Überlastungen von Cross (außer das Erzwingen eines bestimmten Rückgabetyps, der in der 6. Zeile des Codes definiert ist.)

3

Ich glaube, Sie dies tun könnte:

template <std::size_t dim> 
auto cross(const Vec<dim, float_t>& rhs) 
{ 
    /*logic goes here, also you can generalize*/  
} 

Diese für jede dim neue Funktion erstellen wird (implizit). Versuchen Sie es auch zur Kompilierungszeit statt zur Laufzeit mithilfe von Spezialisierungen.

+0

Ja, ich las irgendwo Beispielcode mit ifs, der Autor behauptete, dass dies beim kompilieren der Zeit gelöst werden würde. Ich weiß immer noch nicht, ob das stimmt, aber es gab mir diese Idee hier. Danke für die Hilfe! – Ch3shire

Verwandte Themen