模板化的复制构造函数失败,具有特定的模板化类型

Mic*_*val 8 c++ constructor type-conversion copy-constructor

由于我的一些代码需要在不同类型的矩阵之间进行隐式转换(例如Matrix<int>to Matrix<double>),我定义了一个模板化的复制构造函数Matrix<T>::Matrix(Matrix<U> const&)而不是标准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;
    // ...
};
Run Code Online (Sandbox Code Playgroud)

通过向复制构造函数添加适当的类型转换,此方法可以在不同类型的矩阵之间完美地转换.令人惊讶的是,在一个简单的复制构造函数可以运行的情况下,它会因malloc错误而失败:where 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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Joh*_*itb 13

它失败,因为模板不会抑制复制构造函数的隐式声明.它将作为一个简单的转换构造函数,当重载决策选择它时,它可用于复制对象.

现在,您可能在某处复制了矩阵,这将使用隐式定义的复制构造函数来执行平面复制.然后,复制的矩阵和副本将在它们的析构函数中删除相同的指针.

此外,为什么template <typename T> template <typename U>需要非常详细的语法

因为涉及两个模板:Matrix,它是一个类模板,以及转换构造函数模板.每个模板都有自己的模板子句及其自己的参数.

<T>顺便说一句,你应该摆脱你的第一线.定义模板时不会出现这样的事情.

这是一个糟糕的解决方案,因为它会导致复制构造函数代码的批量重复

您可以定义一个成员函数模板,它将完成工作,并从转换构造函数和复制构造函数委托.这样,代码不会重复.


理查德在评论中提出了一个很好的观点,这使得我修改了我的答案.如果从模板生成的候选函数比隐式声明的复制构造函数更好地匹配,则模板"wins",并且将调用它.以下是两个常见示例:

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)
}
Run Code Online (Sandbox Code Playgroud)

如果任何成员具有,则复制构造函数也可以具有非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)
}
Run Code Online (Sandbox Code Playgroud)