Kann man den Operator + bei vector<> überladen?



  • pumuckl schrieb:

    alternativ kann man den Operator in den jeweiligen Scope oder Namespace importieren per using-Direktive.

    Das war meine Intention. Ich würde wahrscheinlich den namespace nehmen, wenn diese Überladung auch für andere Dateien von Interesse ist und die direkte Implementierung in die Quelldatei, wenn du das nur in einem File brauchst (weil da der namespace nicht viel bringt).



  • Man kann sich das auch alles sparen, und vernünftigerweise eine freie Funktion anstelle eines höchst fragwürdigen Operators verwenden.



  • hustbaer schrieb:

    Man kann sich das auch alles sparen, und vernünftigerweise eine freie Funktion anstelle eines höchst fragwürdigen Operators verwenden.

    👍
    Wenn ich jetzt nicht viel zu tun hätte, würde ich filisofisch werden, warum uns das nicht vorher eingefallen ist.



  • volkard schrieb:

    filisofisch

    Wenn dann: filosofisch oder vielohsofisch



  • drakon schrieb:

    Dann lass die Deklaration im Header und mach lediglich eine Definition in der Quelldatei. Andere Dateien haben da dann keinen Zugriff drauf.

    Alternativ wäre es noch eine Möglichkeit das in einen namespace zu packen, aber ich denke, dass das nicht nötig ist.

    Ich möchte auch nochmal darauf hinweisen, dass ein solcher Operator nicht Teil der Schnittstelle von Vektoren im Sinne dieses Artikels ist. Er wird nicht über ADL gefunden und es kann sein, dass er durch einen anderen operator+ verdeckt wird -- je nachdem, wo man ihn deklariert und von wo aus man ihn benutzen will. In so einer Situation hilft auch keine using-Direktive sonder nur eine using-Deklaration.

    kk



  • volkard schrieb:

    hustbaer schrieb:

    Man kann sich das auch alles sparen, und vernünftigerweise eine freie Funktion anstelle eines höchst fragwürdigen Operators verwenden.

    👍
    Wenn ich jetzt nicht viel zu tun hätte, würde ich filisofisch werden, warum uns das nicht vorher eingefallen ist.

    Naja. Eigentlich wurde das ja bereits von Rüdiger als dritte Antwort angesprochen. Nicht direkt, aber prinzipiell hat er genau das damit gesagt.
    Allerdings bin ich für meinen Teil davon ausgegangen, dass der Fragesteller sich durchaus bewusst ist, dass man da eine freie Funktion nehmen kann. Über die Gründe lassen sich natürlich diskutieren, aber das ist ja eigentlich ein anderes Problem.



  • volkard schrieb:

    hustbaer schrieb:

    Man kann sich das auch alles sparen, und vernünftigerweise eine freie Funktion anstelle eines höchst fragwürdigen Operators verwenden.

    👍
    Wenn ich jetzt nicht viel zu tun hätte, würde ich filisofisch werden, warum uns das nicht vorher eingefallen ist.

    v = v1 + v2 + v3 + v4 + v5;
    
    // Oder:
    
    v = add_vector(add_vector(add_vector(add_vector(v1, v2), v3), v4), v5);
    


  • ipsec schrieb:

    volkard schrieb:

    hustbaer schrieb:

    Man kann sich das auch alles sparen, und vernünftigerweise eine freie Funktion anstelle eines höchst fragwürdigen Operators verwenden.

    👍
    Wenn ich jetzt nicht viel zu tun hätte, würde ich filisofisch werden, warum uns das nicht vorher eingefallen ist.

    v = v1 + v2 + v3 + v4 + v5;
    
    // Oder:
    
    v = add_vector(add_vector(add_vector(add_vector(v1, v2), v3), v4), v5);
    

    Beides nicht.



  • volkard schrieb:

    Beides nicht.

    Wie dann deiner Meinung nach?



  • drakon schrieb:

    volkard schrieb:

    Beides nicht.

    Wie dann deiner Meinung nach?

    Ich vermute, ich würde mir was einfallen lassen, um die temporären vectoren zu vermeiden.



  • Sowas in der Art?

    template<class T>
    class adder
    {
    public:
    	adder(vector<T>& v) : vec(v) {}
    	adder<T>& add(const vector<T>& v) { vec.insert(vec.begin(), v.begin(), v.end()); return *this; }
    	vector<T>& get() { return vec; }
    	operator vector<T>&() { return get(); }
    
    private:
    	vector<T>& vec;
    };
    
    template<class T>
    adder<T> get_adder(vector<T>& v)
    {
    	return adder<T>(v);
    }
    
    template<class T>
    adder<T> add(vector<T>& v1, const vector<T>& v2)
    {
    	return adder<T>(v1).add(v2);
    }
    // ...
    
    get_adder(v1).add(v2).add(v3).add(v4).add(v5);    // 1
    add(v1, v2).add(v3).add(v4).add(v5);              // 2
    


  • Wieso nicht einfach insert() aufrufen?



  • hustbaer schrieb:

    Wieso nicht einfach insert() aufrufen?

    Wahrscheinlich wegen der schlechteren Übersichtlichkeit und der fehlenden Möglichkeit, mehrere Container in einem temporären Ausdruck zu verketten.

    Man könnte zur Vermeidung unnötiger temporärer Objekte eine Zwischenklasse schreiben, welche als Rückgabetyp des operator+ eingesetzt wird und die beiden Quell-Vectors referenziert. Durch einen Konvertierungsoperator nach std::vector<T> könnte die Verkettung schlussendlich ausgeführt werden.



  • Nexus schrieb:

    Man könnte zur Vermeidung unnötiger temporärer Objekte eine Zwischenklasse schreiben, welche als Rückgabetyp des operator+ eingesetzt wird und die beiden Quell-Vectors referenziert. Durch einen Konvertierungsoperator nach std::vector<T> könnte die Verkettung schlussendlich ausgeführt werden.

    Das geht in Richtung "Expression Templates". Man könnte sich alternativ auf einen optimierenden Compiler verlassen und so etwas machen:

    vector<int> operator+(vector<int> a, vector<int> const& b)
    {
      vector<int> result;
      result.swap(a);
      result.insert(result.end(),b.begin(),b.end());
      return result; // NRVO applicable
    }
    

    Mein GCC 4.4 hält dank copy elision (beim "pass-by-value" und "return value optimization") es bei der Zeile

    vector<int> x = a + b + c + d;
    

    dann nicht für nötig, unnötige vector-Kopien zu erstellen. Aber ich weiß nicht, ob der Microsoft Compiler das auch hinbekommt.

    In C++0x muss man sich da noch weniger Sorgen um unnötige Kopien machen. 🙂

    kk



  • krümelkacker schrieb:

    Nexus schrieb:

    Man könnte zur Vermeidung unnötiger temporärer Objekte eine Zwischenklasse schreiben, welche als Rückgabetyp des operator+ eingesetzt wird und die beiden Quell-Vectors referenziert. Durch einen Konvertierungsoperator nach std::vector<T> könnte die Verkettung schlussendlich ausgeführt werden.

    Das geht in Richtung "Expression Templates". Man könnte sich alternativ auf einen optimierenden Compiler verlassen und so etwas machen:

    vector<int> operator+(vector<int> a, vector<int> const& b)
    {
      vector<int> result;
      result.swap(a);
      result.insert(result.end(),b.begin(),b.end());
      return result; // NRVO applicable
    }
    

    Mein GCC 4.4 hält dank copy elision (beim "pass-by-value" und "return value optimization") es bei der Zeile

    vector<int> x = a + b + c + d;
    

    dann nicht für nötig, unnötige vector-Kopien zu erstellen. Aber ich weiß nicht, ob der Microsoft Compiler das auch hinbekommt.

    In C++0x muss man sich da noch weniger Sorgen um unnötige Kopien machen. 🙂

    kk

    Unnötige Kopien?
    x=a+b+c+d;
    wäre doch gut mit
    x=a;x+=b;x+=c;x+=d;
    Macht der GCC wirklich das?



  • volkard schrieb:

    Unnötige Kopien?
    x=a+b+c+d;
    wäre doch gut mit
    x=a;x+=b;x+=c;x+=d;

    Du hast hier etwas weggelassen. In meinem Beispiel stand "vector<int> x = …". Ich initialisiere mit dem Ausdruck und mache keine Zuweisung. Damit kann man sich eine unnötige Kopie gegenüber

    vector<int> x;
    x = a+b+c;
    

    sparen (zumindest beim GCC). Klar, mit op+= kann man's auch machen. Aber es ist doch nett, dass das mit + fast genauso gut geht. 🙂

    Macht der GCC wirklich das?

    Der aktuelle GCC kann fast alle erlaubten "copy elisions" durchführen (wenn man mal Funktionen mit mehreren returns ignogiert). Einzige Ausnahme ist RVO bei Funktionsparametern, die per Wert übergeben wurden. Ich wüsste auch nicht, wie man die ABI umbauen müsste, damit so etwas möglich wird. Es wird halt vom Standard erlaubt. Aber kein Compiler kann das. Weil das kein Compiler kann, habe ich das swap im operator+.

    Der GCC 4.4 macht mit

    inline ding operator+(ding lhs, ding const& rhs)
    {
      ding result;
      result.swap(lhs);
      result += rhs;
      return result;
    }
    …
      ding x = a+b+c;
    

    aus der letzten Zeile über copy elisions ungefähr folgendes

    ding tmp1 = a;
      ding tmp2;
      tmp2.swap(tmp1);  
      tmp2 += b;
      ding x;
      x.swap(tmp2);
      x += c;
      tmp2.~ding();
      tmp1.~ding();
    

    Ich sehe hier keine "unnötige Kopie" eines ding-Objekts. Unter der Annahme, dass der Defaultkonstruktor und das Swap sehr effizient sind, sollte es zwischen

    vector<int> x=a+b+c+d;
    

    und

    vector<int> x=a; x+=b; x+=c; x+=d;
    

    keine signifikanten Laufzeitunterschiede geben.

    kk



  • Hallo!

    Ich wollte mich noch einmal bei allen bedanken, die mir hier geholfen haben!
    Hat alles super funktioniert.

    Gruß
    Thorsten


Anmelden zum Antworten