如何为模板类定义一个单一的拷贝构造函数?

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;
};