【问题标题】:How to define a single copy constructor for template classes?如何为模板类定义单个复制构造函数?
【发布时间】:2022-01-18 20:08:00
【问题描述】:
#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;
}

在这里,我有一个矩阵类,它可以是intdouble 或任何数值的矩阵。

我想定义一个复制构造函数,它接受具有任何数值类型的矩阵并复制其元素。

例如,假设 m1Matrix&lt;double&gt; = {1.1, 2.2, 3.3, ...},Matrix&lt;int&gt; m2 = m1 应将 m2 设置为 {1, 2, 3, ...}。

另外,我想要一个移动构造函数,但是除了它自己的类型(在这个例子中,它是T)之外的任何类型都有一个移动构造函数没有任何意义。

这是因为我要窃取指向数字数组的指针,并且要这样做,它必须是相同的类型。

定义仅接受Matrix&lt;T&gt; 的移动构造函数会自动删除Matrix&lt;T&gt; 的复制构造函数。

我意识到由于我尝试制作的复制构造函数中的参数不一定是相同类型的,所以它不被认为是复制构造函数,除非我专门为Matrix&lt;T&gt;编写复制构造函数(注释复制构造函数),代码将无法编译。

但是即使我没有复制构造函数,我也有一个可以接受任何类型矩阵的构造函数。为什么要专门找拷贝构造函数?

如何只定义一次复制构造函数,并让它处理任何类型的矩阵?

【问题讨论】:

  • "我如何只定义一次复制构造函数,并让它处理任何类型的矩阵?" 恐怕不是,来自cppreference:一个副本T 类的构造函数是一个非模板构造函数,其第一个参数是T&amp;‍const T&amp;‍volatile T&amp;‍const volatile T&amp;‍,或者没有其他参数,或者其余参数都有默认值。
  • Matrix&lt;double&gt; m2 = m1; -- 这不是复制构造函数,因为类型不同。您必须编写一个“普通”构造函数,它接受一个 A 并从中创建一个 B。
  • converting example(仅适用于 ctor - 如果需要,也可以添加转换赋值运算符)。
  • 我同意它不再是复制构造函数,但它是一个有效的构造函数,可以接受任何类型的矩阵。如果我没有复制构造函数,为什么会出现编译错误?为什么不调用这个模板构造函数,它接受任意类型的矩阵?
  • fwiw,您不需要在您的问题中添加“更新”(或“编辑”)。如果有人想查看编辑历史,他们可以在这里:stackoverflow.com/posts/70367073/revisionsminimal reproducible example 是问题的重要部分,将其放在一些“不是真正的代码”之后,并且大量文字使问题难以阅读

标签: c++ oop templates constructor


【解决方案1】:

但是即使我没有复制构造函数,我也有一个可以接受任何类型矩阵的构造函数。为什么要专门找拷贝构造函数?

在重载决议中,它不是找到最好的可用函数。相反,它是找到最好的功能并尝试使用它。如果由于访问限制或被删除而无法访问,则会出现编译器错误。

在你的例子中,你有一个模板构造函数,它标记了Matrix(const Matrix&lt;double&gt;&amp; matrix) (#1),它还找到了由编译器隐式生成的Matrix(const Matrix&lt;double&gt;&amp; matrix) = delete (#2),因为你有一个用户提供的移动构造函数。在重载决议中,如果两个函数具有完全相同的签名,并且其中一个是模板的特化,则选择非模板版本。在这种情况下,#2 已被删除,因此访问已删除函数时会出现错误。

所以回答

如何只定义一次复制构造函数,并让它处理任何类型的矩阵?

你不能。如果您希望 Foo&lt;T&gt; 可以从另一个 Foo&lt;T&gt; 复制,那么您需要提供一个复制构造函数。如果您希望Foo&lt;T&gt; 可以从Foo&lt;U&gt; 复制,那么您需要为此添加一个转换构造函数。理想情况下,您会使用std::vector 之类的东西作为矩阵元素的底层存储,如果这样做,那么您只需遵循零规则,您的班级就会变成

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-24
    • 1970-01-01
    相关资源
    最近更新 更多