Solo estaba jugando con g ++ 4.7 (una de las instantáneas posteriores) con -std = c ++ 11 habilitado. Traté de compilar algo de mi base de código existente y un caso que falló me confunde un poco.
Agradecería que alguien me pudiera explicar lo que está pasando.
Aquí está el código:
#include <utility>
#include <iostream>
#include <vector>
#include <string>
int main ( )
{
std::string s = "abc";
// 1 ok
std::pair < std::string, int > a = std::make_pair ( s, 7 );
// 2 error on the next line
std::pair < std::string, int > b = std::make_pair < std::string, int > ( s, 7 );
// 3 ok
std::pair < std::string, int > d = std::pair < std::string, int > ( s, 7 );
return 0;
}
Entiendo que make_pair está destinado a usarse como el caso (1) (si especifico los tipos, entonces también podría usar (3)), pero no entiendo por qué está fallando en este caso.
El error exacto es:
test.cpp: In function ‘int main()’:
test.cpp:11:83: error: no matching function for call to ‘make_pair(std::string&, int)’
test.cpp:11:83: note: candidate is:
In file included from /gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/utility:72:0,
from test.cpp:1:
/gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/stl_pair.h:274:5:
note: template<class _T1, class _T2> constexpr std::pair<typename std::__decay_and_strip<_T1>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&)
/gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/stl_pair.h:274:5:
note: template argument deduction/substitution failed:
test.cpp:11:83: note: cannot convert ‘s’ (type ‘std::string {aka std::basic_string<char>}’) to type ‘std::basic_string<char>&&’
Una vez más, la pregunta aquí es simplemente "¿qué está pasando?" Sé que puedo solucionar el problema eliminando la especificación de la plantilla, pero solo quiero saber qué está fallando aquí debajo de las cubiertas.
- g ++ 4.4 compila este código sin problemas.
- La eliminación de -std = c ++ 11 también se compila con código sin problemas.

std::vectorconstrucción . Al menos este produce un error de compilación y no un cambio silencioso en la semántica.Respuestas:
Esta no es la forma en
std::make_pairque debe usarse; no se supone que debe especificar explícitamente los argumentos de la plantilla.C ++ 11
std::make_pairtoma dos argumentos, de tipoT&&yU&&, dondeTyUson parámetros de tipo de plantilla. Efectivamente, se ve así (ignorando el tipo de retorno):template <typename T, typename U> [return type] make_pair(T&& argT, U&& argU);Cuando llama
std::make_pairy especifica explícitamente los argumentos del tipo de plantilla, no se realiza ninguna deducción de argumentos. En cambio, los argumentos de tipo se sustituyen directamente en la declaración de plantilla, lo que produce:[return type] make_pair(std::string&& argT, int&& argU);Tenga en cuenta que ambos tipos de parámetros son referencias de rvalue. Por lo tanto, solo se pueden vincular a rvalues. Esto no es un problema para el segundo argumento que pasa
7, porque es una expresión rvalue.s, sin embargo, es una expresión lvalue (no es temporal y no se está moviendo). Esto significa que la plantilla de la función no coincide con sus argumentos, razón por la cual obtiene el error.Entonces, ¿por qué funciona cuando no especifica explícitamente qué
Ty quéUestán en la lista de argumentos de la plantilla? En resumen, los parámetros de referencia de rvalue son especiales en las plantillas. Debido en parte a una característica del lenguaje llamada colapso de referencias , un parámetro de referencia rvalue de tipoA&&, dondeAes un parámetro de tipo de plantilla, se puede vincular a cualquier tipo deA.No importa si
Aes un lvalue, un rvalue, const-calificado, volatile-calificado o no calificado, unA&&puede vincularse a ese objeto (nuevamente, si y solo siAes en sí mismo un parámetro de plantilla).En su ejemplo, hacemos la llamada:
make_pair(s, 7)Aquí,
ses un valor l de tipostd::stringy7es un valor r de tipoint. Dado que no especifica los argumentos de la plantilla para la plantilla de la función, la deducción de los argumentos de la plantilla se realiza para averiguar cuáles son los argumentos.Para enlazar
s, un lvalue, toT&&, el compilador deduceTque esstd::string&, produciendo un argumento de tipostd::string& &&. Sin embargo, no hay referencias a referencias, por lo que esta "doble referencia" se colapsa para convertirse enstd::string&.ses un partido.Es sencillo al unen
7aU&&: el compilador puede deducirUqueint, produciendo un parámetro de tipoint&&, que se une al éxito7porque es un valor de lado derecho.Hay muchas sutilezas con estas nuevas funciones de lenguaje, pero si sigue una regla simple, es bastante fácil:
fuente