2017-04-16 2 views
3

Das obige stammt von einem video von David Stone. Was ich nicht verstehen kann ist, warum emplace_back der explizite Konstruktor aufrufen? Ich sehe nichts in dem C++ - Standard, der dieses legit macht. Erst nachdem ich David Stones Youtube-Video gehört habe, habe ich davon erfahren.std :: map emplace schlägt mit expliziten Konstruktor fehl

Jetzt versuche ich das gleiche mit std::map.

map<int, A> m; 
m.insert(pair<int, A>(1, 2)); // compiler error since no implicit constructor 
m.emplace(1, 2); // compiler error since no implicit constructor 

Warum schlägt emplace hier fehl? Wenn emplace_back kann explizite Konstruktor aufrufen, warum nicht emplace das gleiche tun?

Antwort

1

m.insert(std::pair<int, A>(1, 2)) kompiliert, ich weiß nicht, warum es nicht für Sie kompiliert. Vielleicht vergessen -std=c++11 Flagge? Das liegt daran, dass der Konstruktor std::pair den Konstruktor explizit aufruft, wenn er die Elemente in first und second kopiert.

Wenn Sie in eine std::map einfügen möchten, müssen Sie einen Schlüssel und einen Wert in einer std::pair angeben. Sie können std::make_pair dafür verwenden:

m.emplace(std::make_pair(1, 2)); 

Dies kompiliert, da das Paar wird an Ort und Stelle in dem Schlüssel/Wert-Paar aufgebaut werden, und der explizite Konstruktor aufgerufen.

+2

Dies hat mit den bedingten expliziten Konstruktoren zu tun, die formell in C++ 17 hinzugefügt wurden, aber von neueren Versionen von GCC in C++ 11 und später implementiert wurden. –

+0

Ich benutzte C++ 14 Flags, aber ich habe gcc Version 4.9.2. Ich habe versucht mit gcc 6.2 und jetzt beide "m.insert (Paar (1, 2)) und m.emplace (1, 2);" kompilieren. Auch für map.emplace glaube ich nicht, dass make_pair benutzt werden muss. –

3

emplace Methode fügt Elemente durch expliziten Aufruf von Konstruktor mit placement new operator ein. Beim Einreihen in die Karte müssen Sie Argumente für die Konstruktion von Schlüssel und Wert separat weiterleiten.

m.emplace 
(
    ::std::piecewise_construct // special to enable forwarding 
, ::std::forward_as_tuple(1) // arguments for key constructor 
, ::std::forward_as_tuple(2) // arguments for value constructor 
); 
2

Die emplace Funktionen aufrufen Konstruktor zum http://eel.is/c++draft/container.requirements.general#15.5

in der Norm beschriebenen

T ist EmplaceConstructible in X von args, für null oder mehr Argumente args, bedeutet, dass der folgende Ausdruck ist wohlgeformt :

allocator_traits<A>::construct(m, p, args)

Dies bedeutet, dass es letztlich zu Ihrem Allokator kommt. Mit Blick auf die Referenz für das, was das bedeutet nennt, können wir http://en.cppreference.com/w/cpp/memory/allocator_traits/construct

überprüfen Wir sehen, dass, wenn der Zuordner nicht über ein Konstrukt Elementfunktion, oder wenn es std::allocator ist, dann ist der Anruf entspricht

::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)

Für std::map<int, A> ist der Typ T in Ihrem Ausdruck std::pair<int const, A> und args... ist . Um zu wissen, ob Ihr Anruf bei emplace wohlgeformt ist, müssen wir nur entscheiden, ob ein Anruf an std::pair<int const, A>(1, 2) gültig ist.Also für das, schauen wir auf die Dokumentation für std::pair: http://en.cppreference.com/w/cpp/utility/pair/pair

Der Konstruktor in Frage steht auf der Liste /*EXPLICIT*/ constexpr pair(const T1& x, const T2& y); (vorausgesetzt, C++ 17). Mit anderen Worten, es ist wie beim Aufruf einer regulären Funktion, die int const & als erstes Argument und A const & als zweites Argument annimmt. A ist nur explizit von int konstruierbar, also ist Ihr Anruf schlecht gebildet. Der Aufruf emplace speichert Sie nur von explicit auf alle Objekte, die Sie direkt erstellen, in diesem Fall nur std::pair, keine Argumente für diesen Typ.

Verwandte Themen