rvalue reference und std::make_pair- hat der VC2012 recht?



  • Ich bekomm gerad eienen Bugreport von jemanden rein, der VC12 verwendet und C++11 scheinbar aktiviert hat. Code der vorher problemlos funktioneirt hat, gibt jetzt einen compilefehler aus, und ich frage mich, ob ich das fixen muss, oder ob der compiler schuld ist:

    folgender Code:

    template<class Iterator1,class Iterator2>
    struct PairIterator{
    
    std::pair<Iterator1,Iterator2> iterators()const{
        return std::make_pair<Iterator1,Iterator2>(m_iterator1,m_iterator2);
    }
    private:
    	Iterator1 m_iterator1;
    	Iterator2 m_iterator2;
    };
    

    Fehlermeldung:

    error C2664: 'std::make_pair' : cannot convert parameter 1 from 'const std::_Vector_iterator<_Myvec>' to 'std::_Vector_iterator<_Myvec> &&'
    

    Mir ist schon irgendwie klar das const Iterator1 nicht an Iterator1&& binden sollte. Aber ich bin mir nicht sicher: sollte in diesem Fall nicht eine temporäre kopie erzeugt werden? Beinhaltet der Standard wirklich library änderungen die nicht rückwärtskompatibel sind? *seufz*



  • Was passiert denn, wenn du die überflüssigen Typangaben bei make_pair weglässt?



  • Ich habe keinen VC12 hier, kanns also selbst nicht austesten.

    aber nach

    http://www.cplusplus.com/reference/utility/make_pair/

    ist die Signatur

    template <class T1, class T2>
      pair<V1,V2> make_pair (T1&& x, T2&& y);  // see below for definition of V1 and V2
    

    also sollten meeine überflüssigen Typangaben keinen Unterschied machen.


  • Mod

    otze schrieb:

    Beinhaltet der Standard wirklich library änderungen die nicht rückwärtskompatibel sind? *seufz*

    Das wäre so ein Fall, ja. Allerdings ist der Code ohnehin 100% sinnlos. Der Sinn von make_pair besteht ja gerade darin, dass die Templateargumente nicht explizit angegeben werden müssen. Andernfalls kann man das pair genausogut direkt erzeugen.

    return std::pair<Iterator1,Iterator2>(m_iterator1,m_iterator2);
    return make_pair_pair(m_iterator1,m_iterator2); // erzeugt pair<const Iterator1&, const Iterator2&> das dann nochmal implizit konvertiert wird
    return {m_iterator1,m_iterator2};
    

    Ein lvalue kan nicht an eine rvalue-Referenz gebunden werden. (und dann kommt noch in diesem Fall die const-Problematik hinzu).



  • Der springende Punkt ist das reference-collapsing, was durch das explizite Angeben der Typen verhindert wird.



  • Um das nochmal deutlich zu sagen:

    otze schrieb:

    Ich habe keinen VC12 hier, kanns also selbst nicht austesten.

    aber nach

    http://www.cplusplus.com/reference/utility/make_pair/

    ist die Signatur

    template <class T1, class T2>
      pair<V1,V2> make_pair (T1&& x, T2&& y);  // see below for definition of V1 and V2
    

    also sollten meeine überflüssigen Typangaben keinen Unterschied machen.

    Doch, ohne die überflüssigen Typangaben sollte es korrekt funktionieren. Nur mit den Typangaben ist es inkompatibel.



  • Sone schrieb:

    Der springende Punkt ist das reference-collapsing, was durch das explizite Angeben der Typen verhindert wird.

    Nein. Der springende Punkt ist dass die explizite Angeben der Typen verhindert dass T1 als XYZ const deduziert wird.



  • Danke. Nach campers post (Möglichkeit Nr.2 im Code) wars dann aber bereits klar :-). Trotzdem danke für die restlichen Mühen die mir das nochmal tiefer einhämmern sollten. Die Message ist angekommen 😉



  • Ich zitiere mal nur sinngemäß:

    camper schrieb:

    // erzeugt pair<const Iterator1&, const Iterator2&> das dann nochmal implizit konvertiert wird
    return make_pair(m_iterator1,m_iterator2);
    

    Das ist falsch. make_pair liefert nur dann ein Paar mit Referenz-Elementen zurück, falls man es entsprechend mit reference_wrapper n füttert.

    Aber ja, der Sinn von make_pair ist schon der, dass man die Typen nicht angeben muss. Sonst könnte man auch direkt pair schreiben. 😉

    Sone hat schon recht. Durch explizite Angabe der Templateargumente wurden aus den Funktionsparametern Rvalue-Referenzen-auf-non-const, welche sich ja nicht mit Lvalues und schon gar nicht mit konstanten Lvalues initialisieren lassen. Es wurde sozusagen perfect forwarding ausgehebelt. Die Templateparameter beschreiben nicht die Ausgabe, sondern die Eingabe einschließlich der Wertkategorie. Der Typ der Ausgabe ist etwas komplizierter. Ggf wird da auch ein reference_wrapper zu einer normalen Referenz ausgepackt.


  • Mod

    krümelkacker schrieb:

    Das ist falsch. make_pair liefert nur dann ein Paar mit Referenz-Elementen zurück, falls man es entsprechend mit reference_wrapper n füttert.

    Stimmt.


Anmelden zum Antworten