GNT sans publicité, site mobile, fonctionnalitées exclusives...

Spécialisation de template et spécialisation de méthode

Le
flure
Bonjour,

Je débute un peu en C++ et notamment pour ce qui concerne les templates.
Je me base sur la documentation que je trouve sur internet pour me
former (notamment http://www.cplusplus.com).
Aujourd'hui, j'ai un problème que je n'arrive pas à résoudre malgré mes
recherches.

Je crée une classe template Matrix qui doit me servir à manipuler des
matrices, ainsi :

templace<int COLS, int ROWS, class T = float>
class Matrix
{
private:
std::vector<T> mData;
public:
// plusieurs méthodes
//

// la méthode qui me pose problème :
void setIdentity();
};

T est là pour permettre de choisir entre float et double, idéalement
j'aurais préféré m'en passer, car il n'y a pas vraiment d'intérêt
(mathématique) à manipuler des matrices de TrucMuches ou autres types
exotiques.

La méthode setIdentity() ne peut fonctionner que lorsque T est float ou
double. Elle initialise toutes les données de mon vector à 0.0 sauf la
diagonale qui est initialisée à 1.
De plus ROWS et COLS doivent être égaux (matrice carrée).

Par exemple pour une Matrix<2, 2, float>, setIdentity ferait cela :

for(unsigned y = 0; y < ROWS; y++)
{
for(unsigned x = 0; x < COLS; x++)
{
if(x == y) mData[x + y * COLS] = 1.0f;
else mData[x + y * COLS] = 0.0f;
}
}

Je voudrais que pour le cas où T n'est ni float ni double cette méthode
ne fasse rien, et pour le cas de float elle utilise 1.0f et 0.0f alors
que pour double elle utiliserait 1.0 et 0.0.

Je pensais spécialiser cette méthode pour cela, mais je ne trouve pas la
bonne syntaxe.

Parmi tant d'autres syntaxes j'ai essayé celle-ci :
template <int ROWS, int COLS, T>
void Matrix<ROWS, COLS, float>::setIdentity()
{
for(unsigned row; row < ROWS; row++)
{
for(unsigned col; col < COLS; col++)
{
if(row == col) mData[col + row * COLS] = 1.0f;
else mData[col + row * COLS] = 0.0f;
}
}
}

Mais évidemment cela ne marche pas.
Donc maintenant j'en ai assez de tâtonner, et je viens chercher l'aide
de ceux qui maîtrisent le sujet. ;)

Merci d'avance pour votre aide, et surtout s'il s'avère que je suis
parti sur une mauvaise piste lors de la création de cette classe,
n'hésitez pas à me le faire savoir

Florent
Lire les 19 réponses

Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 4
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Marc Guéguen
Le #23669261
"flure" news:4e50413c$0$28932$
Bonjour,

Je débute un peu en C++ et notamment pour ce qui concerne les templates.
Je me base sur la documentation que je trouve sur internet pour me former
(notamment http://www.cplusplus.com).
Aujourd'hui, j'ai un problème que je n'arrive pas à résoudre malgré mes
recherches.

Je crée une classe template Matrix qui doit me servir à manipuler des
matrices, ainsi :

templace<int COLS, int ROWS, class T = float>
class Matrix
{
private:
std::vector<T> mData;
public:
// plusieurs méthodes
// ...

// la méthode qui me pose problème :
void setIdentity();
};

T est là pour permettre de choisir entre float et double, idéalement
j'aurais préféré m'en passer, car il n'y a pas vraiment d'intérêt
(mathématique) à manipuler des matrices de TrucMuches ou autres types
exotiques.

La méthode setIdentity() ne peut fonctionner que lorsque T est float ou
double. Elle initialise toutes les données de mon vector à 0.0 sauf la
diagonale qui est initialisée à 1.
De plus ROWS et COLS doivent être égaux (matrice carrée).

Par exemple pour une Matrix<2, 2, float>, setIdentity ferait cela :

for(unsigned y = 0; y < ROWS; y++)
{
for(unsigned x = 0; x < COLS; x++)
{
if(x == y) mData[x + y * COLS] = 1.0f;
else mData[x + y * COLS] = 0.0f;
}
}

Je voudrais que pour le cas où T n'est ni float ni double cette méthode ne
fasse rien, et pour le cas de float elle utilise 1.0f et 0.0f alors que
pour double elle utiliserait 1.0 et 0.0.



Il n'est pas facile de spécialiser dans les cas où ce n'est pas...
Dans ton cas, définit la méthode inline de façon à ce qu'elle ne fasse rien
par défaut et spécialise pour les cas spécifiques

templace<int COLS, int ROWS, class T = float>
class Matrix
{
private:
std::vector<T> mData;
public:
// plusieurs méthodes
// ...

// la méthode qui me pose problème :
void setIdentity() {}
};


Je pensais spécialiser cette méthode pour cela, mais je ne trouve pas la
bonne syntaxe.

Parmi tant d'autres syntaxes j'ai essayé celle-ci :
template <int ROWS, int COLS, T>
void Matrix<ROWS, COLS, float>::setIdentity()
{
}



la syntaxe correcte est :
template <int ROWS, int COLS> // pas de T !
void Matrix<ROWS, COLS, float>::setIdentity()
{
//....
}
flure
Le #23669651
On 21/08/2011 11:12, Marc Guéguen wrote:
la syntaxe correcte est :
template <int ROWS, int COLS> // pas de T !
void Matrix<ROWS, COLS, float>::setIdentity()
{
//....
}




Bonjour,

Merci pour ton aide, malheureusement, je viens d'essayer cette syntaxe,
et ça ne compile toujours pas, voici mon message d'erreur :

../src/math3d/matrix.h:85:45: error: invalid use of incomplete type
‘class Matrix<ROWS, COLS, float>’
../src/math3d/matrix.h:47:1: error: declaration of ‘class Matrix<ROWS,
COLS, float>’

Je précise que je suis sous Ubuntu en 64 bits, et que j'utilise GCC
4.5.2, si jamais ça peut influer...

Je devrais sans doute m'acheter un bon bouquin de C++, ça pourrait
m'aider...

Florent
Fabien LE LEZ
Le #23669711
On Sun, 21 Aug 2011 01:20:28 +0200, flure
template<int COLS, int ROWS, class T = float>



Pourquoi le type "int" ici ? D'autant que tu utilises "unsigned" plus
loin :

for(unsigned y = 0; y < ROWS; y++)



Logiquement, ton compilateur doit râler.

Mieux vaut mettre "unsigned int" partout, puisqu'une matrice avec un
nombre négatif de colonnes, ça n'a aucun sens.



méthode



Note en passant : je déconseille l'utilisation du mot "méthode" en C++
car sa définition n'est pas vraiment univoque. Mieux vaut dire
"fonction membre".

Je voudrais que pour le cas où T n'est ni float ni double cette méthode
ne fasse rien,



Mauvaise idée. Si tu appelles une fonction dans un contexte où ça n'a
pas de sens, tu veux obtenir une erreur de compilation.

et pour le cas de float elle utilise 1.0f et 0.0f alors
que pour double elle utiliserait 1.0 et 0.0.



Je ne vois pas bien l'utilité. Assigne 1 et 0, et tu auras
(gratuitement) une fonction qui marche bien pour tous les types
numériques.

Pour répondre directement à ta question : à ma connaissance,
spécialiser ainsi une fonction membre n'est pas possible. Il faudrait
spécialiser toute ta classe.

Pour faire les choses proprement, il faudrait commencer par le
commencement : est-il bien utile que setIdentity() soit une fonction
membre ?

Si tu peux implémenter setIdentity() en tant que fonction libre, qui
appelle éventuellement des fonctions membres, fais-le. Inutile de
faire grossir ta classe pour rien.

Par exemple :

template <unsigned int ROWS, class T>
void setIdentity (Matrix<ROWS,ROWS,T>& m)
{
for (unsigned int y = 0; y < ROWS; y++)
{
for (unsigned int x = 0; x < ROWS; x++)
{
m.SetValeur (x, y, (x == y) ? 1 : 0);
}
}
}

Ici, tu as tout ce qu'il te faut :

- La fonction n'est définie que pour une matrice carrée ;
- Si le type T n'est pas un type numérique, assigner 1 donnera une
erreur de compilation.

Bien sûr, il faut que tu aies une fonction membre Matrix::SetValeur().
flure
Le #23669871
On 21/08/2011 13:51, Fabien LE LEZ wrote:
Ici, tu as tout ce qu'il te faut :

- La fonction n'est définie que pour une matrice carrée ;
- Si le type T n'est pas un type numérique, assigner 1 donnera une
erreur de compilation.



Effectivement, ça marche très bien comme ça, merci.
Et c'est vrai qu'il me semble plus logique de sortir de la classe toutes
les fonctions membres qui ne servent que dans le cadre de la géométrie
(identité, création de matrice de rotation, translation, projection etc...).
Ce qui me chifonne c'est d'avoir plein de fonctions libres, je n'aime
pas beaucoup. Je préfère avoir une classe avec que des fonctions membres
statiques pour faire ces manipulations géométriques sur les matrices.
Mais bon, je suppose que ce n'est qu'une histoire de goût.

Bien sûr, il faut que tu aies une fonction membre Matrix::SetValeur().



En effet, j'avais déjà surchargé operator() spécialement pour cela.

Merci pour l'aide précieuse.

Florent
Fabien LE LEZ
Le #23669971
On Sun, 21 Aug 2011 14:48:03 +0200, flure
Ce qui me chifonne c'est d'avoir plein de fonctions libres, je n'aime
pas beaucoup.



Tu viens de Java, non ?

Je te conseille la lecture de cette page :
http://www.gotw.ca/gotw/084.htm
Publicité
Suivre les réponses
Poster une réponse
Anonyme