Como algunos de mi código requerido conversión implícita entre matrices de diferentes tipos (por ejemplo Matrix<int>
a Matrix<double>
), he definido un constructor de copia de plantilla Matrix<T>::Matrix(Matrix<U> const&)
en lugar de la estándar Matrix<T>::Matrix(Matrix<T> const&)
:con plantilla constructor de copia falla con el tipo de plantilla específica
template <typename T> class Matrix {
public:
// ...
template <typename U> Matrix(Matrix<U> const&);
// ...
private
unsigned int m_rows, m_cols;
T *m_data;
// ...
};
Con un tipo de conversión apropiado agregado al copiador-constructor, este método se convierte sin problemas entre matrices de diferentes tipos. Sorprendentemente, falla con un error malloc en la misma situación donde funcionaría un simple constructor de copia: donde U == T
. Efectivamente, la sobrecarga del copy-constructor con la firma predeterminada Matrix<T>::Matrix(Matrix<T> const&)
resuelve el problema.
Esta es una solución deficiente, ya que resulta en la duplicación al por mayor del código de copia y constructor (Literalmente una copia y pegado sin cambios). Más importante aún, no entiendo por qué hay un error doble malloc
sin el código duplicado. Además, ¿por qué es necesaria la sintaxis extremadamente detallada de template <typename T> template <typename U>
aquí en lugar de la estándar, y mucho más sucinta, template <typename T, typename U>
?
Fuente completa del método con plantilla, compilado con G ++ v4.0.1 en Mac OS 10.5.
template <typename T> template <typename U> Matrix<T>::Matrix(Matrix<U> const& obj) {
m_rows = obj.GetNumRows();
m_cols = obj.GetNumCols();
m_data = new T[m_rows * m_cols];
for (unsigned int r = 0; r < m_rows; ++r) {
for (unsigned int c = 0; c < m_cols; ++c) {
m_data[m_rows * r + c] = static_cast<T>(obj(r, c));
}
}
}
Tu explicación del error de malloc suena perfectamente. ¿Hay alguna razón específica por la cual los compiladores no pueden usar una función de miembro de plantilla como copia-constructor? Gracias por la información y los consejos para evitar la duplicación de código. –
Si tiene esa plantilla, todavía no es una función. Solo el uso de este con un argumento de plantilla genera una función (miembro) a partir de él (llamada especialización). Esta es también la razón por la cual las plantillas de miembros no pueden ser virtuales: usted no sabe de antemano qué funciones se generan a partir de ella. –
Eso tiene mucho sentido; esto no funciona por la sencilla razón de que uno necesita reenviar los parámetros de la plantilla o incluir el origen completo de la implementación. Gracias de nuevo. –