2011-01-29 18 views
11

Según la documentation que:¿Cómo funciona boost :: unordered_map.emplace (Args && ... args)?

Inserts un objeto, construido con los args argumentos, en el recipiente si y sólo si no hay ningún elemento en el recipiente con una clave equivalente.

Pero los únicos objetos que se pueden insertar en un unordered_map tienen tipo std::pair<Key const, Mapped> (ya que tanto una clave y un valor son necesarios para un objeto a ser insertado), que es conocido por tener un constructor con exactamente dos argumentos. Entonces, ¿por qué usa la forma de función variadica? Seguramente hay algo que no entiendo completamente acerca de esto.

Respuesta

8

Véase this AS artículo en emplace_back contra push_back. Básicamente, permite que un objeto se construya a partir de los argumentos que se pasan a él sin necesidad de crear el objeto que se pasará primero. Se ahorra en gastos generales al eliminar una construcción de copia que normalmente ocurre como resultado de la creación de objetos para insertar.

Por lo que puede salirse con la suya:

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

en lugar de

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

Aún mejor, (y si no me equivoco), puede ir a través de esta ruta:

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

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

Y tomado de la Wiki en C++0x:

Debido a la naturaleza de la redacción de las referencias rvalue, y a algunas modificaciones a la redacción de las referencias lvalue (referencias regulares), las referencias rvalue permiten a los desarrolladores proporcionar un reenvío de funciones perfecto. Cuando se combina con plantillas variadic, esta capacidad permite plantillas de funciones que pueden enviar perfectamente argumentos a otra función que toma esos argumentos particulares. Esto es más útil para reenviar parámetros de constructor, para crear funciones de fábrica que llamarán automáticamente al constructor correcto para esos argumentos particulares.

que funciona de la siguiente manera:

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)...)); 
    } 
} 

Una vez más, robado descaradamente del artículo de Wiki mencionado anteriormente.

+0

El último ejemplo me parece extraño. Supongamos que tenemos 2 constructores para 'Clave':' Clave (int) 'y' Clave (int, int) 'y 2 para' Valor': 'Valor (int, int)' y 'Valor (int)', ¿cómo es? el compilador va a desambiguar en el caso de construir un par 'Key/Value' –

+0

Primero que llegue, primero atendido, tomo? Entonces crea un 'X (int, int)' primero y luego un 'X (int)'. Lo probará más tarde y publicará de nuevo. También podría no compilar y lanzar un error de tiempo de compilación "ambiguo". – Xeo

+0

@Matthieu M. No tengo idea, de verdad. El problema es que la especificación no está completamente formalizada en este momento, por lo que no podemos saber con certeza cómo se debe responder a este tipo de pregunta hasta que lo esté. Lo que necesitamos es un abogado de idiomas que venga y aclare las ambigüedades que tenga mi respuesta. Yo votaría eso en un abrir y cerrar de ojos. – wheaties

5

Ahora que el ++ biblioteca estándar de C ha integrado esa parte de Boost:

De 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 es una constante que no deja ninguna ambigüedad acerca de cómo se utilizarán los argumentos

  • La primera tupla se usará para estafar struct la tecla
  • La segunda para construir el valor