模板化拷贝构造失败,并需要不同类型(例如Matrix
到Matrix
),I所定义的模板拷贝构造Matrix::Matrix(Matrix const&)
而不是标准的Matrix::Matrix(Matrix const&)
的矩阵之间的隐式转换的特定模板类型
template <typename T> class Matrix {
public:
// ...
template <typename U> Matrix(Matrix<U> const&);
// ...
private
unsigned int m_rows, m_cols;
T *m_data;
// ...
};
通过将适当的类型转换添加到复制构造函数中,此方法在不同类型的矩阵之间完美转换。令人惊讶的是,在一个简单的复制构造函数会起作用的情况下,它会失败并出现malloc错误:其中U == T
。果然,使用默认的Matrix<T>::Matrix(Matrix<T> const&)
签名重载复制构造函数可以解决问题。
这是一个糟糕的解决方案,因为它导致了复制构造函数代码的批量复制(字面上是不变的复制和粘贴)。更重要的是,我不明白为什么没有重复代码时出现双免费malloc
错误。此外,为什么在这里需要非常详细的template <typename T> template <typename U>
语法而不是标准,并且简洁得多,template <typename T, typename U>
?
模板化方法的完整源代码,在Mac OS 10.5上使用G ++ v4.0.1编译。
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));
}
}
}
它失败了,因为模板不能抑制复制构造函数的隐式声明。它将作为一个简单的转换构造函数,在重载解析选择它时可用于复制对象。
现在,您可能已将您的矩阵复制到某处,这会使用隐式定义的复制构造函数来完成平面复制。然后,复制的矩阵和副本都将在其析构函数中删除相同的指针。
而且,为什么是极其冗长
template <typename T> template <typename U>
语法要求
因为有两个模板涉及:矩阵,这是一个类模板,以及转换构造函数模板。每个模板都有自己的模板子句和自己的参数。
顺便说一句,您应该在第一行中删除<T>
。定义模板时不会出现这样的事情。
这是一个贫穷的解决方案,因为它会导致拷贝构造函数代码
您可以定义一个成员函数模板,这将做的工作的批发重复,代表从两个转换构造函数和复制构造函数。这样,代码不会重复。
理查德在评论中提出了一个很好的观点,这让我修改了我的答案。如果从模板生成的候选函数比隐式声明的复制构造函数更好匹配,那么模板将“胜出”,并且将被调用。这里有两个常见的例子:
struct A {
template<typename T>
A(T&) { std::cout << "A(T&)"; }
A() { }
};
int main() {
A a;
A b(a); // template wins:
// A<A>(A&) -- specialization
// A(A const&); -- implicit copy constructor
// (prefer less qualification)
A const a1;
A b1(a1); // implicit copy constructor wins:
// A(A const&) -- specialization
// A(A const&) -- implicit copy constructor
// (prefer non-template)
}
拷贝构造函数可以有一个非const引用参数也一样,如果它的任何成员都有
struct B { B(B&) { } B() { } };
struct A {
template<typename T>
A(T&) { std::cout << "A(T&)"; }
A() { }
B b;
};
int main() {
A a;
A b(a); // implicit copy constructor wins:
// A<A>(A&) -- specialization
// A(A&); -- implicit copy constructor
// (prefer non-template)
A const a1;
A b1(a1); // template wins:
// A(A const&) -- specialization
// (implicit copy constructor not viable)
}
我不是从你的问题完全清楚,但我怀疑发生了什么事是默认的拷贝构造函数(只有一个成员拷贝)正在你的代码的某些地方使用。请记住,不仅您实际编写的代码使用复制构造函数 - 编译器也会使用它。
您对malloc错误的解释听起来很明显。编译器不能使用模板成员函数作为复制构造函数是否存在特定的原因?感谢您提供的信息和建议以避免代码重复。 – 2009-08-09 00:32:29
如果你有这个模板,那它还不是一个功能。只有使用某个模板参数才能生成(成员函数)(称为专业化)。这也是成员模板不能成为虚拟的原因:您不能预先知道从中生成了哪些功能。 – 2009-08-09 01:02:02
这非常有道理 - 这不适用于需要转发声明模板参数或包含实现的完整源代码的原因。再次感谢。 – 2009-08-09 03:33:15