模板复制构造函数因特定模板类型而失败

Templated copy-constructor fails with specific templated type(模板复制构造函数因特定模板类型而失败)

本文介绍了模板复制构造函数因特定模板类型而失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于我的一些代码需要在不同类型的矩阵之间进行隐式转换(例如 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)
}

这篇关于模板复制构造函数因特定模板类型而失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:模板复制构造函数因特定模板类型而失败

基础教程推荐