La plantilla "constructor de copia" no impide el constructor de movimientos generado por el compilador
Considere el siguiente programa y los comentarios que contiene:
template<class T>
struct S_ {
S_() = default;
// The template version does not forbid the compiler
// to generate the move constructor implicitly
template<class U> S_(const S_<U>&) = delete;
// If I make the "real" copy constructor
// user-defined (by deleting it), then the move
// constructor is NOT implicitly generated
// S_(const S_&) = delete;
};
using S = S_<int>;
int main() {
S s;
S x{static_cast<S&&>(s)};
}
La pregunta es: ¿por qué la definición del usuario del constructor de plantilla (que efectivamente actúa como un constructor de copia cuando U = T) no impide que el compilador genere el constructor de movimiento, mientras que, por el contrario, si el usuario defino la copia "real"? constructor (eliminándolo), entonces el constructor de movimiento no se genera implícitamente (el programa no se compilaría)? (Probablemente la razón es que la "versión de plantilla" no respeta la definición estándar de constructor de copia también cuando T = U?).
Lo bueno es que aparentemente eso es lo que quiero. De hecho, necesito todos los constructores de copiar y mover y todos los operadores de asignación de mover y copiar que el compilador generaría implícitamente como si S estuviera simplemente definido como template<class U> S{};
más el constructor de plantilla para las conversiones de other S<U>
. Por norma general, ¿puedo confiar en la definición anterior de S para tener todas las cosas mencionadas que necesito? En caso afirmativo, podría evitar "incumplirlos" explícitamente.
La respuesta es simple: no existe (!) un constructor de copias de plantilla. Incluso si el parámetro de la plantilla coincide con el parámetro de un constructor de copia, no es un constructor de copia.
Ver 12.8 Copiar y mover objetos de clase.
Un constructor que no es de plantilla para la clase X es un constructor de copia si su primer parámetro es de tipo X&, const X&, volatile X& o const volatile X&, y no hay otros parámetros o todos los demás parámetros tienen argumentos predeterminados (8.3.6 ). [Ejemplo: X::X(const X&) y X::X(X&,int=1) son constructores de copia.
Lo mismo se aplica al constructor de movimientos.
No existe un constructor de copias con plantilla. El constructor de copia normal (sin plantilla) aún se genera y coincide mejor que el de plantilla con la firma que usted proporcionó (las cosas se vuelven más complicadas con las referencias "universales" incluidas en la mezcla, pero eso está fuera de tema).