模板复制构造函数因特定模板类型而失败
由于我的一些代码需要在不同类型的矩阵之间进行隐式转换(例如 Matrix<int>
到 Matrix<double>
),我定义了一个模板化的复制构造函数 Matrix<T>::Matrix(Matrix<U> const&)
代替标准的 Matrix<T>::Matrix(Matrix<T> const&)
::p>
As some of my code required implicit conversion between matrices of different types (e.g. Matrix<int>
to Matrix<double>
), I defined a templated copy constructor Matrix<T>::Matrix(Matrix<U> const&)
instead of the standard Matrix<T>::Matrix(Matrix<T> 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&)
签名重载复制构造函数可以解决问题.
With an appropriate typecast added to the copy-constructor, this method flawlessly converted between matrices of different types. Surprisingly, it fails with a malloc error in the very situation where a simple copy-constructor would function: where U == T
. Sure enough, overloading the copy-constructor with the default Matrix<T>::Matrix(Matrix<T> const&)
signature solves the problem.
这是一个糟糕的解决方案,因为它会导致大量复制构造函数代码(字面意思是未更改的复制和粘贴).更重要的是,我不明白为什么在没有重复代码的情况下会出现 double-free malloc
错误.此外,为什么非常冗长的 template <typename T>这里需要的模板
语法与标准相反,并且更简洁,template
?
This is a poor solution, as it results in the wholesale duplication of the copy-constructor code (Literally an unchanged copy-and-paste). More importantly, I do not understand why there is a double-free malloc
error without the duplicate code. Furthermore, why is the extremely verbose template <typename T> template <typename U>
syntax required here as opposed to the standard, and much more succinct, template <typename T, typename U>
?
模板化方法的完整源代码,在 Mac OS 10.5 上使用 G++ v4.0.1 编译.
Full source of the templated method, compiled using G++ v4.0.1 on 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));
}
}
}
推荐答案
失败是因为模板没有抑制复制构造函数的隐式声明.它将作为一个简单的转换构造函数,可用于在重载决议选择对象时复制对象.
It fails because a template doesn't suppress the implicit declaration of a copy constructor. It will serve as a simple converting constructor, which can be used to copy an object when overload resolution selects it.
现在,您可能在某处复制了矩阵,这将使用隐式定义的复制构造函数来执行平面复制.然后,复制的矩阵和副本都将在它们的析构函数中删除相同的指针.
Now, you probably copied your matrix somewhere, which would use the implicitly defined copy constructor which does a flat copy. Then, the copied matrix and the copy would both in their destructor delete the same pointer.
此外,为什么非常冗长的 template <typename T>模板<typename U>
语法要求
Furthermore, why is the extremely verbose
template <typename T> template <typename U>
syntax required
因为涉及到两个模板:Matrix(类模板)和转换构造函数模板.每个模板都应该有自己的模板子句和自己的参数.
Because there are two templates involved: The Matrix, which is a class template, and the converting constructor template. Each template deserves its own template clause with its own parameters.
顺便说一句,你应该去掉第一行中的 <T>
.定义模板时不会出现这样的事情.
You should get rid of the <T>
in your first line, by the way. Such a thing does not appear when defining a template.
这是一个糟糕的解决方案,因为它会导致大量复制构造函数代码
This is a poor solution, as it results in the wholesale duplication of the copy-constructor code
您可以定义一个成员函数模板来完成工作,并从转换构造函数和复制构造函数进行委托.这样代码就不会重复了.
You can define a member function template, which will do the work, and delegate from both the converting constructor and the copy constructor. That way, the code is not duplicated.
理查德在评论中提出了一个很好的观点,这让我修改了我的答案.如果从模板生成的候选函数比隐式声明的复制构造函数更匹配,那么模板获胜",它将被调用.下面是两个常见的例子:
Richard made a good point in the comments which made me amend my answer. If the candidate function generated from the template is a better match than the implicitly declared copy constructor, then the template "wins", and it will be called. Here are two common examples:
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)
}
复制构造函数也可以有一个非常量引用参数,如果它的任何成员有
A copy constructor can have a non-const reference parameter too, if any of its members has
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)
}
相关文章