2008-11-16 4 views
5

Ich habe eine vektorartige Klasse, die ein Array von Objekten vom Typ "T" enthält, und ich möchte 4 arithmetische Operatoren implementieren, die die Operation auf jedes Element anwenden:C++: Operator zweier intrinsischer Typen als Funktionsobjekt verwenden

// Constructors and other functions are omitted for brevity. 
template<class T, unsigned int D> 
class Vector { 

public: 
    // Add a value to each item: naive implementation. 
    void operator += (const T&) { 
     for (int i = 0; i < D; ++i) { 
      data[i] += value; 
     } 
    } 
    void operator -= (const T&) { ... } 
    void operator *= (const T&) { ... } 
    void operator /= (const T&) { ... } 

private: 
    T items[D]; 
}; 

Da die Betreiber den gleichen Standardcode (Schleifen über jedes Element und die Anwendung geeigneten Betriebes) enthalten, dachte ich, dass ich es verallgemeinern könnte:

ist
template<class T, unsigned int D> 
class Vector { 

public: 
    void operator += (const T& value) { do_for_each(???, value); } 
    void operator -= (const T& value) { do_for_each(???, value); } 
    void operator *= (const T& value) { do_for_each(???, value); } 
    void operator /= (const T& value) { do_for_each(???, value); } 

private: 
    void 
    do_for_each(std::binary_function<void, T, T>& op, T value) { 
     std::for_each(data, data + D, std::bind2nd(op, value)); 
    } 

    T data[D]; 
}; 

nun das Problem, wie gehe ich ein Operator, der zwei intrins nimmt ic-Typen und liefert void zu do_for_each, wie im obigen Beispiel dargestellt? C++ lässt mich diesen Trick nicht für intrinsische Typen machen ("T::operator+=" funktioniert nicht, wenn "int" ist).

+0

Sie könnten 'data' vs' Elemente '... – Alastair

+0

dank beheben wollen, fest es auch unter –

+0

Fragen wie diese sind, warum Freunde Freunde nicht überladen Betreiber – Jonathan

Antwort

8

Zuerst sollten Sie wirklich eine Referenz von Ihrem Operator + = zurückgeben, da Sie sie später verwenden können, um Operator +, Operator- usw. zu implementieren. Ich werde das entsprechend ändern.

Auch Ihr do_for_each muss eine Vorlage sein, da es den genauen Typ des Funktionsobjekts kennen muss, da binäre Funktionsobjekte keine polymorphen Klassen sind. Für den eigentlichen Betrieb, möchten Sie std::transform verwenden:

template<class T, unsigned int D> 
class Vector { 

public: 
    Vector& operator += (const T& value) { 
     do_for_each(std::plus<T>(), value); 
     return *this; 
    } 

    Vector& operator -= (const T& value) { 
     do_for_each(std::minus<T>(), value); 
     return *this; 
    } 

    Vector& operator *= (const T& value) { 
     do_for_each(std::multiplies<T>(), value); 
     return *this; 
    } 

    Vector& operator /= (const T& value) { 
     do_for_each(std::divides<T>(), value); 
     return *this; 
    } 

private: 
    template<typename BinFun> 
    void do_for_each(BinFun op, const T& value) { 
     std::transform(data, data + D, data, std::bind2nd(op, value)); 
    } 

    T data[D]; 
}; 

std::transform wird nur jedes Element auf das Funktionsobjekt übergeben, und weist das Ergebnis zurück an den Iterator als drittes Argument angegeben.

+0

Ich war gerade dabei, genau das gleiche zu schreiben! :) Prost, +1! –

+0

Sie sollten eine Konstante von den Operatoren zurückgeben, so dass dies (was wirklich schwer zu lesen/herauszufinden) nicht möglich ist: (v + = v2) - = v3 – SoapBox

+0

SoapBox: Ich sehe keine besonderen Gründe zu verbiete das. Auch, wenn Sie nicht-const zurückgeben, tun Sie, was die meisten nicht tun. Dies geschieht gegen das Prinzip der geringsten Überraschung. Es ist vollkommen vernünftig, f (a + = b) zu machen; beispielsweise. –

2

Sie sollten wirklich einen Blick auf Boost Operators, eine Header-only-Bibliothek, die wirklich das Erstellen von orthogonalen und konsistenten arithmetischen Operator Überladungen vereinfacht.

Spezifisch: Sie könnten feststellen, dass die Ableitung von boost::operators::integer_arithmatic<T> spart Ihnen eine Menge der Wiederholung dieser Klasse.

1

Ich denke, Litb ist auf dem richtigen Weg und beantwortete die genaue Frage.
Aber ich denke, das ist die falsche Lösung.

Ich möchte nicht die do_for_each() verwenden, sondern die std :: transform() direkt:

template<class T, unsigned int D> 
class Vector 
{ 

    public: 
    Vector& operator += (const T& value) { 
     std::transform(data, data + D, data, std::bind2nd(std::plus<T>(),value)); 
     return *this; 
    } 

    Vector& operator -= (const T& value) { 
     std::transform(data, data + D, data, std::bind2nd(std::minus<T>(),value)); 
     return *this; 
    } 

    Vector& operator *= (const T& value) { 
     std::transform(data, data + D, data, std::bind2nd(std::multiplies<T>(),value)); 
     return *this; 
    } 

    Vector& operator /= (const T& value) { 
     std::transform(data, data + D, data, std::bind2nd(std::divides<T>(),value)); 
     return *this; 
    } 

    private: 
    T data[D]; 
}; 
Verwandte Themen