2014-12-18 9 views

risposta

30

Il tipo di elemento di std::map<K, V> è in realtà std::pair<K, V>, in modo che quando si sta emplacing in una mappa, gli argomenti sarà trasmesso al costruttore di std::pair. Ecco perché non puoi passare solo la chiave: std::pair<K, V> non può essere costruita da un singolo argomento (a meno che non sia un'altra coppia dello stesso tipo). Puoi passare zero argomenti, ma la chiave sarà inizializzata dal valore, che è probabilmente non è quello che vuoi.

Nella maggior parte dei casi, i valori in movimento sarà a buon mercato (e le chiavi sarà piccola e copiabile) e si dovrebbe davvero solo fare qualcosa di simile:

M.emplace(k, V{}); 

dove V è il tipo mappato. Sarà inizializzato a valore e spostato nel contenitore. (La mossa potrebbe anche essere eli- minata, non ne sono sicuro)

Se non è possibile spostarsi e si ha veramente bisogno che lo V sia costruito sul posto, è necessario utilizzare il costruttore di costruzione a tratti ...

M.emplace(std::piecewise_construct, std::make_tuple(k), std::make_tuple()); 

Questo provoca std::pair per costruire il primo elemento utilizzando k e il secondo elemento con zero argomenti (valore di inizializzazione).

+0

Perché non 'forward_as_tuple' invece di' make_tuple'? – Yakk

+0

@Yakk Bene, in questo caso, per risparmiare un po 'di digitazione. Ovviamente ci sono casi in cui è necessario 'forward_as_tuple'. – Brian

+9

Si noti che un semplice 'M [k];' avrà lo stesso effetto di quel malarkey 'piece_construct'. –

10

È possibile creare in modo esplicito un pair e passarlo a map::emplace oppure utilizzare lo piecewise construction constructor di std::pair.

struct foo {}; 

std::map<int, foo> m; 

m.emplace(std::pair<int, foo>(1, {})); 
m.emplace(std::piecewise_construct, 
      std::forward_as_tuple(2), 
      std::forward_as_tuple()); 

Live demo

5

Ho avuto lo stesso problema quando ho dovuto creare un std::map di oggetti std::mutex. Il problema è che std::mutex non è né copiabile né mobile, quindi ho dovuto costruirlo "sul posto".

La risposta accettata non funziona per questo caso (M.emplace(k, V{}); ha bisogno che V sia mobile). E non volevo usare l'opzione std::piecewise_construct complicata e meno leggibile (vedi sopra in altre risposte).

La mia soluzione è molto più semplice: basta usare il operator[] - creerà il valore utilizzando il suo costruttore predefinito e restituirà un riferimento ad esso. Oppure troverà e restituirà un riferimento all'elemento già esistente senza crearne uno nuovo.

std::map<std::string, std::mutex> map; 

std::mutex& GetMutexForFile(const std::string& filename) 
{ 
    return map[filename]; // constructs it inside the map if doesn't exist 
} 
Problemi correlati