2016-04-01 9 views
0

Ich versuche emplace() zu verwenden, um einen map<K,V> Eintrag zu erstellen (mit Boost). Der Schlüsselobjektkonstruktor arg wird durch die Vorlagenmagie korrekt weitergeleitet, aber der V object Konstruktor arg wird const, also funktioniert es nicht.Argument forwarding für emplace() macht Konstruktorargumente const

#include <boost/container/map.hpp> 

class A { 
    public: 
    /**/  A(int n) { } 
    friend bool operator<(const A &a1, const A &a2) { return false; } 
} ; 

class B { 
    public: 
    /**/  B(const char *str) { } 
} ; 

class C { 
    public: 
    /**/  C(B &b) { } 
} ; 

int 
main(int, char **) 
{ 
    boost::container::map<A,B> m1; 
    boost::container::map<A,C> m2; 
    B       b("Foo"); 
    C       c(b); // <--- this works OK. 

    m1.emplace(1, "Hello"); 
    m2.emplace(2, b); // <----- this fails! 
} 

Der Fehler ist:

Error: /usr/local/include/boost/container/detail/pair.hpp:128:38: error: no matching function for call to C::C(const B&), second(::boost::forward<V>(v)) 

Etwas über die emplace Argument Weiterleitung schaltet b in const b in der letzten Zeile. Ich weiß, dass es eine boost::bla_bla_bla geben muss, die ich anwenden kann, damit es funktioniert, aber ich konnte es nicht finden.

Kann jemand helfen?

+0

Compiler ist g ++ (Debian 4.9.2-10) 4.9.2, Boost Version 1.60.0 –

+1

Es stellt sich heraus, ich brauchte ein zusätzliches Befehlszeilenargument, um diese Version von g ++ zu C++ - 11 zu bekommen. Einmal hinzugefügt, alles funktioniert! (g ++ -std = C++ 11 foo.cc) –

Antwort

1

Beachten Sie, dass dies funktioniert, wenn Sie dies mit -std=c++11 (oder höher) kompilieren. Warum das der Fall ist, brauchte ein bisschen Graben - ich benutze eine etwas ältere Version von Boost (1.56), aber ich bezweifle, dass sich das zwischen den beiden Releases stark geändert hat.

Die Verwendung von emplace erfordert in der Regel eine perfekte Weiterleitung. Das bedeutet, dass alle Argumente wie unter std::forward<Args>(args)... weitergeleitet werden. Darunter stützt sich die Referenz auf kollabierende und bewegende Semantiken - dies ist alles C++ 11-Gebiet und hat in C++ 03 kein Analog.

Wenn wir für pair in den Boost-Code graben (wo es tatsächlich den Fehler zu erzeugen), dann ist dies der Konstruktor es zu nennen ist versucht:

template<class U, class V> 
pair(BOOST_FWD_REF(U) u, BOOST_FWD_REF(V) v) 
    : first(::boost::forward<U>(u)) 
    , second(::boost::forward<V>(v)) 
{} 

Leider BOOST_FWD_REF (die in move/core.hpp ist) ist ein die folgenden:

#define BOOST_FWD_REF(TYPE)\ 
    const TYPE & \ 
// 

#define BOOST_FWD_REF(TYPE)\ 
    const TYPE & \ 
// 

Wenn Ihr Compiler nicht rvalue Referenzen erkennt, wird dies dann const TYPE& werden.

Es gibt ein wenig Diskussion über diese on the boost archives list.

Die einfachste Lösung ist einfach mit std=c++11 kompilieren.

+0

Vielen Dank! Ich hatte den C++ - 11-Teil herausgefunden und rannte bei meiner Lektüre über rvalue-Referenzen, verstand aber nicht genug von den umgebenden Informationen, um alles zu einer umfassenden Antwort zusammenzufassen (wie Sie es getan haben). –

Verwandte Themen