0

Ich bin auf der Suche nach Ratschlägen zur Implementierung einer spezialisierten "max" -Funktion für einen benutzerdefinierten Datentyp, der auch mit skalaren Typen wie float funktioniert. Der Datentyp, den ich schreibe, ist ein Wrapper für einen Vektor (schließlich ein SIMD-Vektor von vier Floats, kein std::vector) und ich möchte eine max-Funktion bereitstellen, um zwei Vektoren zu vergleichen und einen neuen Vektor zurückzugeben, der das Maximum jedes Elements ist . Dies ist anders als std::max, die den Vergleichsoperator verwendet, aber das Konzept ist das gleiche. Das Problem ist, dass ich eine generische Funktion namens do_max(T x, T y) habe, die max auf die Eingänge anwendet. Ich brauche diese Funktion, um für beide Skalarschwimmereingaben (z. B. do_max<float>(0.1f, 0.2f)) und meine Vektorklasse (z. B. do_max<MyVector>(v0, v1)) zu arbeiten.C++ - Wie spezialisiere ich einen benutzerdefinierten Typ für std :: max ohne Vergleichsoperatoren zu überladen?

Beachten Sie, dass das Überladen von MyVectors Vergleichsoperatoren keine Option ist, da ich solche mit sehr unterschiedlichen SIMD-Intrinsics verwende: Sie erzeugen einen Ganzzahlvektor mit 1, 0, -1 für jeden Elementvergleich, anstatt einen booleschen Wert zurückzugeben Ergebnis.

Der Code, den ich unten nicht über kompilieren, wenn Sie die float f0 = ... Zeilen aus kommentieren:

// compile with: g++ -std=c++11 max.cc -o max 
#include <algorithm> 
#include <vector> 

class MyVector { 
public: 
    MyVector(float x0, float x1, float x2, float x3) : storage_ { x0, x1, x2, x3 } {}; 

    friend MyVector max(MyVector lhs, const MyVector & rhs); 

private: 
    std::vector<float> storage_; 
}; 

MyVector max(MyVector lhs, const MyVector & rhs) { 
    for (size_t i = 0; i < lhs.storage_.size(); ++i) { 
    lhs.storage_[i] = std::max(lhs.storage_[i], rhs.storage_[i]); 
    } 
    return lhs; 
} 

template<typename T> 
T do_max(const T & x, const T & y) { 
    // if this is std::max then it won't compile for MyVector 
    return max(x, y); 
} 

int main(int argc, char * argv[]) { 

    MyVector v0 { 0.1, 0.2, 0.3, 0.4 }; 
    MyVector v1 { 0.4, 0.3, 0.2, 0.1 }; 

    MyVector v2 = do_max(v0, v1); 

    // Comment out the following line to successfully compile. 
    // However I'd like this to work for scalar types too: 
    float f0 = do_max(0.1f, 0.2f); 

    return 0; 
} 

ich ein Gefühl, das ich einen Weg brauchen habe, dass max Funktion Entschlossenheit std::max für skalare Typen zu machen, und mein Fach max Freund-Funktion für den MyVector-Typ.

Wie definiere ich eine Max-Funktion, die auf diese Weise funktioniert? Ist es besser, std::max zu vergessen und meine eigene Max-Funktion zu verwenden, die für MyVector spezialisiert ist und auch Implementierung für skalare Typen wie float bietet?

Der Hintergrund dafür ist, dass ich einen Datenpfad implementiere, von dem ich hoffe, dass er sowohl mit MyVector als auch mit skalaren Typen arbeitet (als parametrisierter Typ zur Kompilierungszeit). Ich habe bereits arithmetische Arbeiten, aber die Lösung für max wird auch mit anderen Funktionen wie min, exp, pow verwendet werden.

Antwort

7

Klassische Lösung:

template<typename T> 
T do_max(const T & x, const T & y) { 
    using std::max; 
    return max(x, y); 
} 

Argument Abhängige Lookup findet Ihr max, für float dies nicht der Fall und man bekommt std::max<float>.

+0

Danke, das funktioniert für mein Beispiel. – meowsqueak

+0

Wissen Sie, warum dies fehlschlägt, wenn ich 'return max (x, y)' durch 'return max (x, y)' '? In diesem Fall sieht es so aus, als ob der Compiler es als Aufruf von 'std :: max (x, y) 'auflöst und mit einem ungültigen Operanden für den' <'Operator fehlschlägt, wenn' do_max 'instanziiert wird. Ich verstehe nicht, warum das Setzen des Typparameters explizit auf 'max' dieses Verhalten ändern würde. – meowsqueak

+1

Ihre Funktion ist keine Vorlage? max ist eine explizite Template-Instanziierung. – MSalters

Verwandte Themen