¿Cómo definir un único constructor de copia para clases de plantilla?
#include <iostream>
template <typename t="">
class Matrix
{
public:
Matrix() = default;
template <typename u="">
Matrix(const Matrix<u>& matrix) {
std::cout << "Copying internal data..." << std::endl;
}
Matrix(Matrix<t>&& matrix) {
std::cout << "Moving internal data..." << std::endl;
}
};
int main() {
Matrix<int> m1{};
Matrix<double> m2 = m1;
Matrix<int> m3 = m1;
}
Aquí, tengo una clase de matriz, puede ser una matriz de int
, un double
, o cualquier valor numérico.
Quiero definir un constructor de copia que acepte una matriz con cualquier tipo numérico y copie sus elementos.
Por ejemplo, supongamos que m1
es una Matrix<double> = {1.1, 2.2, 3.3, ...}
, Matrix<int> m2 = m1
debería establecer m2
como {1, 2, 3, …}.
También, quiero tener un constructor de movimiento, pero no tiene sentido tener un constructor de movimiento para cualquier tipo excepto su propio tipo (en este ejemplo, es T
).
Esto se debe a que voy a robar el puntero que apunta a la matriz de números, y para hacerlo, debe ser del mismo tipo.
Definir un constructor de movimiento que acepte solo Matrix<t>
automáticamente elimina el constructor de copia para Matrix<t>
.
Me di cuenta de que como el parámetro en el constructor de copia que intenté hacer no necesariamente es del mismo tipo, no se considera un constructor de copia, y a menos que escriba un constructor de copia específicamente para Matrix<t>
(el constructor de copia comentado), el código no se compilará.
Pero incluso si no tengo un constructor de copia, tengo un constructor que acepta una matriz de cualquier tipo. ¿Por qué busca específicamente el constructor de copia?
¿Cómo defino mi constructor de copia solo una vez y que pueda manejar matrices de cualquier tipo?
davy.ai
Para definir un constructor de copia que funcione con matrices de cualquier tipo, puedes utilizar una técnica llamada “copia e intercambio”.
Primero, defines una función de intercambio que intercambia los datos internos de dos matrices:
Luego, en el constructor de copia, creas una copia temporal de la matriz de entrada e intercambias los datos internos con la copia temporal. Esto asegura que el constructor de copia funcionará con matrices de cualquier tipo:
Ahora, cuando creas una
Matrix<double>
y la asignas a unaMatrix<int>
, se llamará al constructor de copia y los datos internos se copiarán y convertirán a un tipo entero.En cuanto a por qué el compilador específicamente busca un constructor de copia, es porque la asignación
Matrix<int> m2 = m1
es en realidad equivalente a llamar al constructor de copia. No solo se está creando un nuevo objeto y copiando los valores, en realidad se está creando un nuevo objeto y construyéndolo utilizando el constructor de copia.