如何为模板类定义一个单一的拷贝构造函数?
How to define a single copy constructor for template classes?
#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(const Matrix<T>& 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;
}
这里,我有一个矩阵class,可以是int
的矩阵,也可以是double
的矩阵,也可以是任意数值
我想定义一个复制构造函数,它接受任何数值类型的矩阵并复制其元素。
例如,假设 m1
是一个 Matrix<double>
= {1.1, 2.2, 3.3, ...},Matrix<int> m2 = m1
应该设置 m2
为 {1 , 2, 3, ...}.
此外,我想要一个移动构造函数,但是为任何类型设置一个移动构造函数没有任何意义,除了它自己的类型(在这个例子中,它是 T
)。
这是因为我要窃取指向数字数组的指针,为此,它必须是同一类型。
定义一个仅接受 Matrix<T>
的移动构造函数会自动删除 Matrix<T>
.
的复制构造函数
我意识到,由于我尝试制作的复制构造函数中的参数不一定是同一类型,因此不能认为它是复制构造函数,除非我专门为[=19=编写一个复制构造函数](注释的复制构造函数),代码将无法编译。
但即使我没有复制构造函数,我也有一个接受任何类型矩阵的构造函数。为什么它专门寻找复制构造函数?
如何只定义一次复制构造函数,并让它处理任何类型的矩阵?
But even if I don't have a copy constructor, I have a constructor that accepts a matrix of any type. Why is it looking specifically for the copy constructor?
在重载决议中,它不是找到最好的可用函数。相反,它是找到最好的功能并尝试使用它。如果它不能因为访问限制或被删除,那么你会得到一个编译器错误。
在你的例子中,你有模板构造函数,它消除了 Matrix(const Matrix<double>& matrix)
(#1
),它还找到了隐式生成的 Matrix(const Matrix<double>& matrix) = delete
(#2
)由编译器提供,因为您有一个用户提供的移动构造函数。在重载决议中,如果两个函数具有完全相同的签名,并且其中一个是模板的特化,则选择非模板版本。在这种情况下,#2
已被删除,因此您会在访问已删除的函数时出错。
所以要回答
How do I define my copy constructor only once, and have it deal with matrices of any type?
你不能。如果您希望 Foo<T>
可以从另一个 Foo<T>
复制,那么您需要提供一个复制构造函数。如果您希望 Foo<T>
可以从 Foo<U>
复制,那么您需要为此添加一个转换构造函数。理想情况下,您会使用 std::vector
之类的东西作为矩阵元素的底层存储,如果这样做,那么您只需遵循零规则,您的 class 就会变成
template <typename T>
class Matrix
{
public:
Matrix() = default;
template <typename U>
Matrix(const Matrix<U>& other) data(other.data.begin(), other.data.end()) {}
private:
std::vector<T> data;
};
#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(const Matrix<T>& 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;
}
这里,我有一个矩阵class,可以是int
的矩阵,也可以是double
的矩阵,也可以是任意数值
我想定义一个复制构造函数,它接受任何数值类型的矩阵并复制其元素。
例如,假设 m1
是一个 Matrix<double>
= {1.1, 2.2, 3.3, ...},Matrix<int> m2 = m1
应该设置 m2
为 {1 , 2, 3, ...}.
此外,我想要一个移动构造函数,但是为任何类型设置一个移动构造函数没有任何意义,除了它自己的类型(在这个例子中,它是 T
)。
这是因为我要窃取指向数字数组的指针,为此,它必须是同一类型。
定义一个仅接受 Matrix<T>
的移动构造函数会自动删除 Matrix<T>
.
我意识到,由于我尝试制作的复制构造函数中的参数不一定是同一类型,因此不能认为它是复制构造函数,除非我专门为[=19=编写一个复制构造函数](注释的复制构造函数),代码将无法编译。
但即使我没有复制构造函数,我也有一个接受任何类型矩阵的构造函数。为什么它专门寻找复制构造函数?
如何只定义一次复制构造函数,并让它处理任何类型的矩阵?
But even if I don't have a copy constructor, I have a constructor that accepts a matrix of any type. Why is it looking specifically for the copy constructor?
在重载决议中,它不是找到最好的可用函数。相反,它是找到最好的功能并尝试使用它。如果它不能因为访问限制或被删除,那么你会得到一个编译器错误。
在你的例子中,你有模板构造函数,它消除了 Matrix(const Matrix<double>& matrix)
(#1
),它还找到了隐式生成的 Matrix(const Matrix<double>& matrix) = delete
(#2
)由编译器提供,因为您有一个用户提供的移动构造函数。在重载决议中,如果两个函数具有完全相同的签名,并且其中一个是模板的特化,则选择非模板版本。在这种情况下,#2
已被删除,因此您会在访问已删除的函数时出错。
所以要回答
How do I define my copy constructor only once, and have it deal with matrices of any type?
你不能。如果您希望 Foo<T>
可以从另一个 Foo<T>
复制,那么您需要提供一个复制构造函数。如果您希望 Foo<T>
可以从 Foo<U>
复制,那么您需要为此添加一个转换构造函数。理想情况下,您会使用 std::vector
之类的东西作为矩阵元素的底层存储,如果这样做,那么您只需遵循零规则,您的 class 就会变成
template <typename T>
class Matrix
{
public:
Matrix() = default;
template <typename U>
Matrix(const Matrix<U>& other) data(other.data.begin(), other.data.end()) {}
private:
std::vector<T> data;
};