2009-08-08 50 views
8

作爲我的一些代碼:模板化拷貝構造失敗,並需要不同類型(例如<code>Matrix<int></code>到<code>Matrix<double></code>),I所定義的模板拷貝構造<code>Matrix<T>::Matrix(Matrix<U> const&)</code>而不是標準的<code>Matrix<T>::Matrix(Matrix<T> const&)</code>的矩陣之間的隱式轉換的特定模板類型

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&)簽名重載複製構造函數可以解決問題。

這是一個糟糕的解決方案,因爲它導致了複製構造函數代碼的批量複製(字面上是不變的複製和粘貼)。更重要的是,我不明白爲什麼沒有重複代碼時出現雙免費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)); 
     } 
    } 
} 

回答

13

它失敗了,因爲模板不能抑制複製構造函數的隱式聲明。它將作爲一個簡單的轉換構造函數,在重載解析選擇它時可用於複製對象。

現在,您可能已將您的矩陣複製到某處,這會使用隱式定義的複製構造函數來完成平面複製。然後,複製的矩陣和副本都將在其析構函數中刪除相同的指針。

而且,爲什麼是極其冗長template <typename T> template <typename U>語法要求

因爲有兩個模板涉及:矩陣,這是一個類模板,以及轉換構造函數模板。每個模板都有自己的模板子句和自己的參數。

順便說一句,您應該在第一行中刪除<T>。定義模板時不會出現這樣的事情。

這是一個貧窮的解決方案,因爲它會導致拷貝構造函數代碼

您可以定義一個成員函數模板,這將做的工作的批發重複,代表從兩個轉換構造函數和複製構造函數。這樣,代碼不會重複。


理查德在評論中提出了一個很好的觀點,這讓我修改了我的答案。如果從模板生成的候選函數比隱式聲明的複製構造函數更好匹配,那麼模板將「勝出」,並且將被調用。這裏有兩個常見的例子:

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

拷貝構造函數可以有一個非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) 
} 
+0

您對malloc錯誤的解釋聽起來很明顯。編譯器不能使用模板成員函數作爲複製構造函數是否存在特定的原因?感謝您提供的信息和建議以避免代碼重複。 – 2009-08-09 00:32:29

+0

如果你有這個模板,那它還不是一個功能。只有使用某個模板參數才能生成(成員函數)(稱爲專業化)。這也是成員模板不能成爲虛擬的原因:您不能預先知道從中生成了哪些功能。 – 2009-08-09 01:02:02

+0

這非常有道理 - 這不適用於需要轉發聲明模板參數或包含實現的完整源代碼的原因。再次感謝。 – 2009-08-09 03:33:15

1

我不是從你的問題完全清楚,但我懷疑發生了什麼事是默認的拷貝構造函數(只有一個成員拷貝)正在你的代碼的某些地方使用。請記住,不僅您實際編寫的代碼使用複製構造函數 - 編譯器也會使用它。

相關問題