2009-08-09 60 views
3

我有一個矩陣類,其大小由模板參數決定。如何避免C++類模板中的無限遞歸

template <unsigned cRows, unsigned cCols> 
class Matrix { 
    ... 
}; 

我的程序使用幾個大小的矩陣,通常是2x2,3x3和4x4。通過使用模板參數而不是運行時參數設置矩陣大小,編譯器可以進行大量內聯和優化。

但現在我需要一個成員函數,它返回一個新的矩陣,它有一個較少的行和一個較少的列。

Matrix<cRows - 1, cCols - 1> Reduced(unsigned row, unsigned col) const { ... } 

這個想法是,它會返回一個矩陣,刪除指定的行和列。實際上,這隻會被稱爲矩陣,它至少有三行三列,最小返回2x2。

編譯器沒有看到下限,所以它陷入了無限遞歸中,試圖實例化具有不斷減小的大小的模板。我試圖把在函數本身兩條線索,這些更小的尺寸就不會發生:

Matrix<cRows - 1, cCols - 1> Reduced(unsigned row, unsigned col) const { 
    static_assert(cRows > 1 && cCols > 1); 
    if (cRows <= 1 || cCols <= 1) throw std::domain_error(); 
    Matrix<cRows - 1, cCols - 1> r; 
    // ... initialize r ... 
    return r; 
} 

無論是static_assert還是if語句來似乎是一個足夠強大的線索,一個爲0x0矩陣將永遠不會被編譯器生成。 (具有諷刺意味的是,它確實抱怨if -statement具有恆定的編譯時間條件。)

有沒有人有關於如何避免此編譯時無限遞歸的任何建議?

回答

12

您需要爲沒有行或無列的Matrix提供專業化。

E.g.

template<unsigned cRows> 
class Matrix< cRows, 0 > 
{ 
    Matrix<cRows - 1, 0> Reduced() { return Matrix<cRows - 1, 0>(); } 
}; 


template<unsigned cCols> 
class Matrix< 0, cCols > 
{ 
    Matrix<0, cCols - 1> Reduced() { return Matrix<0, cCols - 1>(); } 
}; 


template<> 
class Matrix< 0, 0 > 
{ 
    Matrix<0, 0> Reduced() { return Matrix<0, 0>(); } 
}; 

你的問題是,試圖與一組特定的模板參數來實例化矩陣精簡功能總是需要實例化矩陣模板一組不同的參數(烏鴉 - 1,cCols -1)。這個遞歸必須在某個地方停止。如果你只處理矩形矩陣,那麼你就可以用更少的專門技術逃脫。

此外,如果您永遠不會使用1x1矩陣(2x2矩陣上的縮減結果),則可以使用完全空的類來停止遞歸。

template<> 
class Matrix< 1, 1 > {}; 
+0

他說2x2是最小的,但我仍然認爲這是最好的。也許可以添加'const int MinimumRows','const int MinimumColumns',這樣它就可以調整。 – GManNickG 2009-08-09 20:09:26

+0

謝謝,這個伎倆。我更進了一步,使'Reduced'成爲非成員函數,使得專業化更容易。 – 2009-08-09 21:00:05

0

您需要明確指定您希望遞歸結束的情況下的行爲。有關更多詳細信息,請參閱this DDJ article。下面是文章一個簡單的例子:

template<int n> 
class META_FACTORIAL 
{ 
public: 
    enum{ 
    RET = n * META_FACTORIAL<n-1>::RET 
    }; 
}; 

template<> 
class META_FACTORIAL<0> 
{ 
public: 
    enum{ RET = 1 }; 
}; 
1

您可以指定不包括該方法烏鴉或cCols的小值的模板特。

1

您對編譯時間和運行時行爲似乎有點困惑,而且我對代碼有些困惑,但我認爲您需要的是模板的值爲0,0的特殊值,它終止遞歸。

如果你還沒有得到它,我建議你閱讀 C++ Templates: The Complete Guide範德沃爾德& Josuttis,其中涵蓋了這類事情的細節。

0

不是專業全班終止遞歸,另一個選擇可能是使用boost::enable_if的功能,使其僅當矩陣大小是2×2以上。