2011-01-29 25 views
11

Secondo il documentation esso:Come funziona boost :: unordered_map.emplace (Args && ... args)?

Inserti un oggetto, costruito con gli argomenti args, nel contenitore se e solo se non v'è alcun elemento il contenitore con una chiave equivalente.

Ma i soli oggetti che possono essere inseriti in un unordered_map hanno tipo std::pair<Key const, Mapped> (perché sia ​​una chiave e un valore sono necessari per un oggetto da inserire), che è noto per prendere un costruttore con esattamente due argomenti. Quindi, perché usa la forma della funzione variadica? Sicuramente c'è qualcosa di cui non capisco completamente questo.

risposta

8

Vedere this SO articolo su emplace_back vs. push_back. Essenzialmente, consente di costruire un oggetto dagli argomenti passati senza dover creare prima l'oggetto da passare. Salva l'overhead rimuovendo una costruzione di copia che normalmente avviene come risultato della creazione di oggetti da inserire.

Così si può ottenere via con questo:

unordered_map<int,int> foo; 
foo.emplace(4, 5); 

invece di

foo.insert(std::make_pair(4, 5)); 

Ancora meglio, (e se non mi sbaglio), si può passare attraverso questo percorso:

struct Bar{ 
    int x,y; 
    Bar(int _x, int _y) : x(_x), y(_y){} 
}; 

unordered_map<int,Bar> baz; 
baz.emplace(4, 5, 6); 

E preso dal Wiki su C++0x:

A causa della natura della dicitura dei riferimenti rvalue e di alcune modifiche alla dicitura per i riferimenti lvalue (riferimenti regolari), i riferimenti rvalue consentono agli sviluppatori di fornire un perfetto inoltro delle funzioni. Quando combinato con modelli variadici, questa abilità consente modelli di funzioni che possono inoltrare perfettamente argomenti a un'altra funzione che accetta quegli argomenti particolari. Questo è molto utile per inoltrare i parametri del costruttore, per creare funzioni di fabbrica che chiameranno automaticamente il costruttore corretto per quegli argomenti particolari.

che funziona in questo modo:

template<typename TypeToConstruct> struct SharedPtrAllocator { 

    template<typename ...Args> std::shared_ptr<TypeToConstruct> construct_with_shared_ptr(Args&&... params) { 
     return std::shared_ptr<TypeToConstruct>(new TypeToConstruct(std::forward<Args>(params)...)); 
    } 
} 

Anche in questo caso, spudoratamente rubato da questo articolo Wiki di cui sopra.

+0

Quest'ultimo esempio sembra strano per me. Supponiamo di avere 2 costruttori per 'Key':' Key (int) 'e' Key (int, int) 'e 2 per' Value': 'Valore (int, int)' e 'Valore (int)', come è il compilatore di andare a disambuiguate nel caso di costruzione di una coppia di 'chiave/Value'? –

+0

primo arrivato, primo servito prendo? Quindi crea prima un 'X (int, int)' poi un 'X (int)'. Lo testerà più tardi e pubblicherà di nuovo. Potrebbe anche non compilare e lanciare un errore di tempo di compilazione "ambiguo". – Xeo

+0

@Matthieu M. Non ne ho idea, davvero. Il problema è che la specifica non è attualmente pienamente formalizzato e quindi non possiamo sapere con certezza come si suppone che questo tipo di domanda a cui rispondere fino a quando non è. Ciò di cui abbiamo bisogno è un avvocato linguistico per venire a chiarire qualsiasi ambiguità abbia la mia risposta. Lo voterei in un batter d'occhio. – wheaties

5

Ora che la libreria standard C++ ha integrato la parte di Boost:

Da http://en.cppreference.com

#include <iostream> 
#include <utility> 
#include <tuple> 

#include <unordered_map> 

int main(){ 
    std::unordered_map<std::string, std::string> m; 

    // uses pair's piecewise constructor 
    m.emplace(std::piecewise_construct, 
     std::forward_as_tuple("c"), 
     std::forward_as_tuple(10, 'c')); 

    for (const auto &p : m) { 
     std::cout << p.first << " => " << p.second << '\n'; 
    } 
} 

std::piecewise_construct è una costante che non lascia alcuna ambiguità su come verranno utilizzati gli argomenti

  • La prima tuple sarà utilizzato per confermare struct la chiave
  • La seconda per costruire il valore
Problemi correlati