En C ++ 11, puede prescindir casi por completo sin make_pair. Mira mi respuesta .
PlagueHammer
2
En C ++ 17, std::make_paires redundante. Hay una respuesta a continuación que detalla esto.
Drew Dormann
Respuestas:
165
La diferencia es que std::pairnecesita especificar los tipos de ambos elementos, mientras std::make_pairque creará un par con el tipo de elementos que se le pasan, sin necesidad de contarlo. Eso es lo que podría reunir de varios documentos de todos modos.
main.cpp:Infunction‘int main()’:
main.cpp:13:13: error: missing template arguments before ‘my_class’MyClass my_class(1);^~~~~~~~
y requiere en cambio trabajar:
MyClass<int> my_class(1);
o el ayudante:
auto my_class = make_my_class(1);
que usa una función regular en lugar de un constructor.
Diferencia para `std :: reference_wrapper
Este comentario menciona que se std::make_pairdesenvuelve std::reference_wrappermientras que el constructor no, así que esa es una diferencia. TODO ejemplo.
"C ++ 17 hace posible esa sintaxis y, por lo tanto, make_pair es redundante". - ¿Por qué no std::make_pairquedó obsoleto en C ++ 17?
andreee
@andreee No estoy seguro, ¿la posible razón es que no crea problemas, por lo que no es necesario romper el código antiguo? Pero no estoy familiarizado con la lógica del comité de C ++, hágame un ping si encuentra algo.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Una cosa útil que he encontrado es que poder especificar los tipos con std :: make_pair <T1, T2> (o1, o2) evita que el usuario cometa el error de pasar los tipos o1 u o2 que no pueden ser implícitamente emitido a T1 o T2. Por ejemplo, pasar un número negativo a un int sin signo. -Wsign-conversion -Werror no detectará este error con el constructor std :: pair en c ++ 11, sin embargo, detectará el error si se utiliza std :: make_pair.
conchoecia
make_pairdesenvuelve envoltorios de referencia, por lo que es diferente de CTAD en realidad.
LF
26
No hay diferencia entre usar make_pairy llamar explícitamente al pairconstructor con argumentos de tipo especificados. std::make_paires más conveniente cuando los tipos son detallados porque un método de plantilla tiene una deducción de tipos basada en sus parámetros dados. Por ejemplo,
Vale la pena señalar que este es un idioma común en la programación de plantillas de C ++. Es conocido como el idioma del generador de objetos, puedes encontrar más información y un buen ejemplo aquí .
Editar Como alguien sugirió en los comentarios (desde que se eliminó), el siguiente es un extracto ligeramente modificado del enlace en caso de que se rompa.
Un generador de objetos permite la creación de objetos sin especificar explícitamente sus tipos. Se basa en una propiedad útil de las plantillas de función que las plantillas de clase no tienen: los parámetros de tipo de una plantilla de función se deducen automáticamente de sus parámetros reales. std::make_paires un ejemplo simple que devuelve una instancia de la std::pairplantilla según los parámetros reales de la std::make_pairfunción.
make_pair crea una copia adicional sobre el constructor directo. Siempre escribo dedef mis pares para proporcionar una sintaxis simple.
Esto muestra la diferencia (ejemplo de Rampal Chaudhary):
Estoy bastante seguro de que la copia adicional se eliminará en todos los casos, si la configuración de optimización del compilador es lo suficientemente alta.
Björn Pollex
1
¿Por qué querrías confiar en las optimizaciones del compilador para la corrección?
sjbx
Obtengo los mismos resultados con ambas versiones, y std::movesolo dentro inserty / o alrededor de lo que sería una referencia sample. Solo cuando cambio std::map<int,Sample>a std::map<int,Sample const&>eso reduzco el número de objetos construidos, y solo cuando elimino el constructor de copias elimino todas las copias (obviamente). Después de hacer ambos cambios, mi resultado incluye una llamada al constructor predeterminado y dos llamadas al destructor para el mismo objeto. Creo que me falta algo. (g ++ 5.4.1, c ++ 11)
John P
FWIW Estoy de acuerdo en que la optimización y la corrección deben ser completamente independientes, ya que este es exactamente el tipo de código que escribes como una verificación de sanidad después de que diferentes niveles de optimización produzcan resultados inconsistentes. En general, recomendaría en emplacelugar de insertsi solo está construyendo un valor para insertar de inmediato (y no desea instancias adicionales). No es mi área de especialización, incluso si puedo decir que tengo uno, sino copiar / mover La semántica introducida por C ++ 11 me ha ayudado mucho.
John P
Creo que me encuentro exactamente con el mismo problema y después de depurar durante toda la noche, finalmente vine aquí.
lllllllllllll
1
a partir de c ++ 11 solo use la inicialización uniforme para pares. Entonces en lugar de:
{1, 2}se puede usar para inicializar un par, pero no se compromete para el tipo de par. Es decir, cuando el uso de auto que tiene que comprometerse a un tipo en el lado derecho: auto p = std::pair{"Tokyo"s, 9.00};.
std::make_pair
es redundante. Hay una respuesta a continuación que detalla esto.Respuestas:
La diferencia es que
std::pair
necesita especificar los tipos de ambos elementos, mientrasstd::make_pair
que creará un par con el tipo de elementos que se le pasan, sin necesidad de contarlo. Eso es lo que podría reunir de varios documentos de todos modos.Vea este ejemplo de http://www.cplusplus.com/reference/std/utility/make_pair/
Aparte de la bonificación de conversión implícita, si no usaras make_pair, deberías hacer
cada vez que asignas a uno, lo que sería molesto con el tiempo ...
fuente
std::make_pair
. Aparentemente es solo por conveniencia.one = {10, 20}
hoy en día, pero no tengo un compilador de C ++ 11 a mano para comprobarlo.make_pair
funciona con tipos sin nombre, incluidas estructuras, uniones, lambdas y otros objetos.Como @MSalters respondió anteriormente, ahora puede usar llaves para hacer esto en C ++ 11 (acaba de verificar esto con un compilador de C ++ 11):
fuente
Los argumentos de la plantilla de clase no se pudieron inferir del constructor antes de C ++ 17
Antes de C ++ 17 no podías escribir algo como:
ya que eso inferiría tipos de plantillas a partir de los argumentos del constructor.
C ++ 17 hace que esa sintaxis sea posible y, por lo tanto,
make_pair
redundante.Antes de C ++ 17,
std::make_pair
nos permitía escribir código menos detallado:en lugar del más detallado:
que repite los tipos y puede ser muy largo.
La inferencia de tipos funciona en ese caso anterior a C ++ 17 porque
make_pair
no es un constructor.make_pair
es esencialmente equivalente a:El mismo concepto se aplica a
inserter
frenteinsert_iterator
.Ver también:
Ejemplo mínimo
Para hacer las cosas más concretas, podemos observar el problema mínimamente con:
main.cpp
luego:
compila felizmente, pero:
falla con:
y requiere en cambio trabajar:
o el ayudante:
que usa una función regular en lugar de un constructor.
Diferencia para `std :: reference_wrapper
Este comentario menciona que se
std::make_pair
desenvuelvestd::reference_wrapper
mientras que el constructor no, así que esa es una diferencia. TODO ejemplo.Probado con GCC 8.1.0, Ubuntu 16.04 .
fuente
std::make_pair
quedó obsoleto en C ++ 17?make_pair
desenvuelve envoltorios de referencia, por lo que es diferente de CTAD en realidad.No hay diferencia entre usar
make_pair
y llamar explícitamente alpair
constructor con argumentos de tipo especificados.std::make_pair
es más conveniente cuando los tipos son detallados porque un método de plantilla tiene una deducción de tipos basada en sus parámetros dados. Por ejemplo,fuente
Vale la pena señalar que este es un idioma común en la programación de plantillas de C ++. Es conocido como el idioma del generador de objetos, puedes encontrar más información y un buen ejemplo aquí .
Editar Como alguien sugirió en los comentarios (desde que se eliminó), el siguiente es un extracto ligeramente modificado del enlace en caso de que se rompa.
Un generador de objetos permite la creación de objetos sin especificar explícitamente sus tipos. Se basa en una propiedad útil de las plantillas de función que las plantillas de clase no tienen: los parámetros de tipo de una plantilla de función se deducen automáticamente de sus parámetros reales.
std::make_pair
es un ejemplo simple que devuelve una instancia de lastd::pair
plantilla según los parámetros reales de lastd::make_pair
función.fuente
&&
desde C ++ 11.make_pair crea una copia adicional sobre el constructor directo. Siempre escribo dedef mis pares para proporcionar una sintaxis simple.
Esto muestra la diferencia (ejemplo de Rampal Chaudhary):
fuente
std::move
solo dentroinsert
y / o alrededor de lo que sería una referenciasample
. Solo cuando cambiostd::map<int,Sample>
astd::map<int,Sample const&>
eso reduzco el número de objetos construidos, y solo cuando elimino el constructor de copias elimino todas las copias (obviamente). Después de hacer ambos cambios, mi resultado incluye una llamada al constructor predeterminado y dos llamadas al destructor para el mismo objeto. Creo que me falta algo. (g ++ 5.4.1, c ++ 11)emplace
lugar deinsert
si solo está construyendo un valor para insertar de inmediato (y no desea instancias adicionales). No es mi área de especialización, incluso si puedo decir que tengo uno, sino copiar / mover La semántica introducida por C ++ 11 me ha ayudado mucho.a partir de c ++ 11 solo use la inicialización uniforme para pares. Entonces en lugar de:
o
Solo usa
fuente
{1, 2}
se puede usar para inicializar un par, pero no se compromete para el tipo de par. Es decir, cuando el uso de auto que tiene que comprometerse a un tipo en el lado derecho:auto p = std::pair{"Tokyo"s, 9.00};
.