c++ - libreria - Comparando dos mapas:: iteradores: ¿por qué necesita el constructor de copia de std:: pair?
libreria vector c++ (3)
Creo que lo encontré después de intentar reducir el error. Primero, la comparación no parece ser necesaria para que el programa no esté bien formado. Luego, el mensaje de error contenía el dtor, así que intenté no crear una instancia del dtor. Resultado:
#include <map>
struct A {
A(A& ); // <-- const missing
};
int main() {
std::map<int, A>* m = new std::map<int, A>();
// note: dtor not (necessarily?) instantiated
}
Pero el mensaje de salida todavía contiene, ahora para la línea donde se llama el ctor de m
:
error: el parámetro para este constructor de copia explícitamente predeterminado es const, pero un miembro o base requiere que no sea const
constexpr pair(const pair&) = default;
Lo que sugiere [dcl.fct.def.default] / 4
Una función provista explícitamente por defecto proporcionada por el usuario (es decir, por defecto explícitamente después de su primera declaración) se define en el punto donde se establece por defecto explícitamente; si tal función se define implícitamente como eliminada, el programa no está bien formado .
[énfasis mío]
Si, como supongo, [class.copy] / 11 dice que este ctor debe definirse como eliminado, entonces se define como eliminado inmediatamente, no solo cuando se usa. Por lo tanto, no se debe requerir una creación de instancias para que el programa no se forme correctamente.
El código muy simple a continuación compila y enlaza sin advertencia en C ++ 98 pero da un error de compilación incomprensible en el modo C ++ 11.
#include <map>
struct A {
A(A& ); // <-- const missing
};
int main() {
std::map<int, A> m;
return m.begin() == m.end(); // line 9
}
El error con -std=c++11
es, gcc versión 4.9.0 20140302 (experimental) (GCC):
ali@X230:~/tmp$ ~/gcc/install/bin/g++ -std=c++11 cctor.cpp In file included from /home/ali/gcc/install/include/c++/4.9.0/bits/stl_algobase.h:64:0, from /home/ali/gcc/install/include/c++/4.9.0/bits/stl_tree.h:61, from /home/ali/gcc/install/include/c++/4.9.0/map:60, from cctor.cpp:1: /home/ali/gcc/install/include/c++/4.9.0/bits/stl_pair.h: In instantiation of ‘struct std::pair’: cctor.cpp:9:31: required from here /home/ali/gcc/install/include/c++/4.9.0/bits/stl_pair.h:127:17: error: ‘constexpr std::pair::pair(const std::pair&) [with _T1 = const int; _T2 = A]’ declared to take const reference, but implicit declaration would take non-const constexpr pair(const pair&) = default; ^
con clang versión 3.5 (tronco 202594)
ali@X230:~/tmp$ clang++ -Weverything -std=c++11 cctor.cpp In file included from cctor.cpp:1: In file included from /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/map:60: In file included from /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/bits/stl_tree.h:63: In file included from /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/bits/stl_algobase.h:65: /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/bits/stl_pair.h:119:17: error: the parameter for this explicitly-defaulted copy constructor is const, but a member or base requires it to be non-const constexpr pair(const pair&) = default; ^ cctor.cpp:9:22: note: in instantiation of template class ''std::pair'' requested here return m.begin() == m.end(); // line 9 ^ 1 error generated.
He estado mirando el código en bits/stl_tree.h
y no entiendo por qué está intentando instanciar std::pair
.
¿Por qué necesita el constructor de copia de std::pair
en C ++ 11?
Nota: el código anterior se extrajo del operador de igualdad (==) no admitido en los iteradores de mapas para los mapas que no se pueden copiar .
SOLUCIÓN
Hay dos problemas desafortunados aquí.
Mensajes de error de mala calidad: la línea 8 ya debería dar un error de compilación, aunque los mensajes de error solo se quejan de la línea 9. Obtener un error en la línea 8 sería muy útil y entender el problema real sería mucho más fácil. Probablemente enviaré un informe de error / solicitud de función si este problema sigue presente en gcc / clang trunk.
El otro tema es lo que escribe ecatmur . Considere el siguiente código:
struct A {
A() = default;
A(A& ); // <-- const missing
};
template<class T>
struct B {
B() = default;
B(const B& ) = default;
T t;
};
int main() {
B<A> b;
}
No se compila. A pesar de que el constructor de copia no es necesario en ninguna parte, todavía se crea una instancia porque está predeterminado en línea, en el cuerpo de la clase; esto conduce al error de compilación. Esto se puede arreglar moviendo el constructor de copia fuera del cuerpo de la clase:
template<class T>
struct B {
B() = default;
B(const B& );
T t;
};
template <class T>
B<T>::B(const B& ) = default;
Todo está bien entonces. Desafortunadamente, std::pair
tiene un constructor de copia en línea definido por defecto.
El constructor de copia de std::pair
no es necesario en este caso, pero como se define de forma predeterminada en línea en la declaración de std::pair
, se crea automáticamente una instancia junto con la instanciación de std::pair
.
Sería posible que la biblioteca estándar proporcione una definición predeterminada no en línea del constructor de copia:
template<class _T1, class _T2>
struct pair
{
// ...
constexpr pair(const pair&);
// ...
};
// ...
template<class _T1, class _T2>
constexpr pair<_T1, _T2>::pair(const pair&) = default;
Sin embargo, esto no estaría de acuerdo con la letra estricta de la norma (cláusula 20.3.2), donde el constructor de copia se define en línea por defecto:
constexpr pair(const pair&) = default;
std::map
usa std::pair
para almacenar pares clave-valor, donde la clave (el primer elemento) es const
.
El error del compilador se relaciona con el constructor de copia requerido para std::pair
, incluso si no se está utilizando (lo cual no creo que sea).
std::pair<int, A>
tiene que ser generado. Esto se requiere primero con la llamada a map :: begin. Como no se proporciona ningún constructor de copia explícito para este tipo, se usa el implícito.
El constructor implícito tendrá la firma T :: T (const T &) solo si todos los miembros no estáticos de T, (tipo S), tienen los constructores de copia S :: S (const S &) (el mismo requisito debe cumplirse para la base de T tipos de constructores de copia). De lo contrario, se utiliza un constructor de copia con la firma T :: T (T &).
El constructor de copias de A no cumple con este requisito, por lo que std :: pair :: pair tiene la firma incorrecta para el STL, que requiere T :: T (const T &).