2010-08-19 2 views
2

Fondamentalement, j'ai une classe matrice comme celui-ci (avec beaucoup de surcharge de l'opérateur et d'autres fonctions supprimées):Templated Matrix Class Non Génération fonctionne correctement

template 
< 
    uint32 TRows, 
    uint32 TCols 
> 
struct Matrix 
{ 
    float values[TRows][TCols]; 

    inline explicit Matrix() 
    { 
    } 

    inline Matrix<TRows - 1, TCols - 1> minor(const uint32 col, const uint32 row) 
    { 
     Matrix<TRows - 1, TCols - 1> matrix; 
     for(int i = 0; i < TRows; ++i) 
      for(int j = 0; j < TCols; ++j) 
      { 
       if(i == col || j == row) continue; 
       matrix.values[i - (i > col)][j - (j > row)] = this->values[i][j]; 
      } 
     return matrix; 
    } 

    inline float determinant() 
    { 
     if(TRows != TCols) throw DimensionError("Matrix is not square"); 

     float det = 0; 

     if(TRows <= 0) 
      det = 0; 
     else if(TRows == 1) 
      det = this->values[0][0]; 
     else if(TRows == 2) 
      det = this->values[0][0] * this->values[1][1] - this->values[1][0] * this->values[0][1]; 
     else 
      for(int j = 0; j < TCols; ++j) 
       det += (j % 2 ? -1 : 1) * this->values[0][j] * this->minor(0, j).determinant(); 

     return det; 
    } 
} 

Je ne comprends pas pourquoi, pour la ligne det += (j % 2 ? -1 : 1) * this->values[0][j] * this->minor(0, j).determinant(); , GCC tente de générer une immense quantité de fonctions:

matrix.cpp:95: instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -49u, unsigned int TCols = -49u]' 
matrix.cpp:95: instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -48u, unsigned int TCols = -48u]' 
matrix.cpp:95: instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -47u, unsigned int TCols = -47u]' 
matrix.cpp:95: instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -46u, unsigned int TCols = -46u]' 
matrix.cpp:95: instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -45u, unsigned int TCols = -45u]' 
matrix.cpp:95: instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -44u, unsigned int TCols = -44u]' 
matrix.cpp:95: instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -43u, unsigned int TCols = -43u]' 
matrix.cpp:95: instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -42u, unsigned int TCols = -42u]' 
matrix.cpp:95: instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -41u, unsigned int TCols = -41u]' 
matrix.cpp:95: instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -40u, unsigned int TCols = -40u]' 
matrix.cpp:95: instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -39u, unsigned int TCols = -39u]' 
matrix.cpp:95: instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -38u, unsigned int TCols = -38u]' 
matrix.cpp:95: instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -37u, unsigned int TCols = -37u]' 
matrix.cpp:95: instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -36u, unsigned int TCols = -36u]' 

Ceci est probablement une erreur dans mon code, mais je ne peux pas pour la vie de me voir où je vais mal. L'aide serait très appréciée! Matrix :: minor (0, j) renvoie une matrice de taille (N-1, N-1).

Répondre

4

L'appel de son déterminant rend le processus récursif, ce qui signifie que vous générez une méthode mineure (et déterminante) pour tous les p entiers, de N à ... -infini?

Avez-vous ajouté une spécialisation pour le cas où N == 1 ou N == 0? Vous devez vous assurer que la récursivité s'arrête!

Essayez d'ajouter quelque chose comme:

template<> 
struct Matrix<1,1> 
{ 
    float values[1][1]; 

    float determinant(){ return values[0][0]; } 
}; 

EDIT: récursivité doit être arrêté au moment de la compilation. L'ajout d'une instruction if dans la méthode n'empêche pas le compilateur de compiler tous les chemins possibles.

+0

Merci! Ça marche! Juste une petite faute de frappe dans votre code - 'float' devrait simplement être' float' :) – rfw

+0

@rfw: C'est une branche dynamique, vous avez besoin d'une branche statique. Ajoutez une spécialisation pour une matrice de taille 0. – GManNickG

0

Je suis d'accord avec « Benoît »

Le fait que même pendant l'exécution vous n'appelez minor fonction sur une matrice « vide » - ne l'empêche pas le compilateur de générer ce code. Pour éviter cela, vous devez jouer avec des spécialisations de modèle explicites. De sorte que même à compiler fois le compilateur ne rencontrera pas les chemins de programme qui mènent à la génération de fonction de modèle infinie.

Comme celui-ci:

template <int N> 
float determinantInternal() 
{ 
    // Standard algoritm for NxN matrix 
    float det = 0; 
    for(int j = 0; j < TCols; ++j) 
     det += (j % 2 ? -1 : 1) * this->values[0][j] * this->minor(0, j).determinant(); 

    return det; 
} 

template <> 
float determinantInternal<0>() 
{ 
    return 0; 
} 

float determinantInternal<1>() 
{ 
    return this->values[0][0]; 
} 

float determinantInternal<2>() 
{ 
    return this->values[0][0] * this->values[1][1] - this->values[1][0] * this->values[0][1]; 
} 

template <> 
float determinant() 
{ 
    if (TRows != TCols) 
     throw DimensionError("Matrix is not square"); 
    // Alternatively you can use something to prevent this from compiling. 
    // This way you produce the compile-time error if attempted to call 
    // determinant on a non-square matrix 
    BOOST_STATIC_ASSERT(TRows == TCols); 

    return determinantInternal<TRows>(); 
} 

Un autre avantage de ce type de spécialisation est que vous gérez différents types de matrice (vide, non carrée, 1x1, NxN) à compilation temps. Par conséquent, vous obtenez un code un peu plus rapide.

De plus, vous pouvez empêcher l'appel determinant sur des matrices non carrées. Dans ce cas, vous obtiendrez une erreur de compilateur/éditeur de liens lors de la tentative, plutôt qu'une exception lors de l'exécution.