模板化复制构造函数失败,具有特定的模板类型 [英] Templated copy-constructor fails with specific templated type

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

问题描述

由于我的一些代码需要在不同类型的矩阵之间进行隐式转换(例如 Matrix Matrix< double> ),我定义了一个模板化的拷贝构造函数 Matrix< T> :: Matrix(Matrix< U> const&),而不是标准的 Matrix ; T> :: Matrix(Matrix< T> const&)

  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&)签名重载复制构造函数可以解决问题。



这是一个很差的解决方案,因为它导致复制构造函数代码的批量复制(字面上没有改变的复制和粘贴)。更重要的是,我不明白为什么没有双重的 malloc 错误,没有重复的代码。此外,为什么非常详细 template< typename T>模板< typename U> 这里要求的语法与标准相反,并且更简洁, template< typename T,typename U>



在Mac OS 10.5上使用G ++ v4.0.1编译的模板方法的完整来源。

  template< typename T> template< typename U>矩阵< T>矩阵(矩阵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 for(unsigned int c = 0; c m_data [m_rows * r + c] = static_cast T(obj(r,c));
}
}
}


解决方案>

它失败,因为模板不会抑制复制构造函数的隐式声明。它将作为一个简单的转换构造函数,当过载分辨率选择它时,它可以用来复制一个对象。



现在,您可能已经将矩阵复制到某处,这将使用隐式定义的复制构造函数执行平面复制。然后,复制的矩阵和副本都会在它们的析构函数中删除同一个指针。


此外,为什么非常详细 template< typename T&


因为涉及到两个模板:Matrix类模板和转换构造函数模板。每个模板都应该拥有自己的带有自己的参数的模板子句。



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


这是一个很差的解决方案,因为它导致复制构造函数代码的大量复制


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






Richard在评论中提出了一个好处,如果从模板生成的候选函数是比隐式声明的复制构造函数更好的匹配,则模板胜利,并且它将被调用。这里有两个常见的例子:

  struct A {
template< typename T&
A(T&){std :: cout<< A(T&); }
A(){}
};

int main(){
A a;
A b(a); //模板wins:
// A&A(A&) - specialization
// A(A const&); - 隐式拷贝构造函数
//(优先级较低)

常量a1;
A b1(a1); //隐藏拷贝构造函数wins:
// A(A const&) - specialization
// A(A&) - 隐式拷贝构造函数
// )
}

复制构造函数也可以有一个非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); //隐含拷贝构造函数wins:
// A&A(A&) - specialization
// A(A& - 隐式拷贝构造函数
//(prefer非模板)

const a1;
A b1(a1); // template wins:
// A(A&) - specialization
//(隐式拷贝构造函数不可行)
}


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

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.

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>?

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.

Furthermore, why is the extremely verbose template <typename T> template <typename U> syntax required

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.

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

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

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆