[C++] Template pour fonction membre

kilian Messages postés 8732 Date d'inscription   Statut Modérateur Dernière intervention   -  
kilian Messages postés 8732 Date d'inscription   Statut Modérateur Dernière intervention   -
Bonjour je vous explique mon problème,

J'ai d'abord une classe modèle comme ceci:
template <typename HeaderType>
class GenericHeader
{
	protected:
		typedef union {
			HeaderType hdr;
			uint8_t      buf[sizeof(HeaderType)];
		} HeaderContent;

		HeaderContent content;

	public:

		/**
		 * Utilisé pour créer un nouveau header à partir de rien.
		 */
		GenericHeader();
		/**
		 * Utilisé pour créer un nouveau header à partir d'un buffer.
		 * @param buf: buffer contenant les données brutes
		 */
		GenericHeader(uint8_t *buf);
		/**
		 * Utilisé pour changer la valeur d'un champs dans les en-têtes.
		 * @param str: Le nom du champs
		 * @param value: La valeur du champs
		 */
		template <typename Field>
		virtual bool set(std::string str, Field value) = 0;
		/**
		 * Utilisé pour obtenir la valeur d'un champs dans les en-têtes.
		 * @param str: Le nom du champs
		 * @return La valeur du champs
		 */
		template <typename Field>
		virtual Field get(std::string str) = 0;
};


J'ai ici deux templates: d'abord HeaderType.
C'est un template qui sera défini lors de l'héritage car pour chaque sous-classe de GenericHeader, j'ai besoin de créer un type union HeaderContent différent.

Puis j'utilise deux autres templates (Field) mais uniquement au niveau des fonctions membres. Je compte instancier leur modèle au moment de leur appel par le biais d'un objet et non pas au moment d'une redéfinition de la classe.
Mais j'ai besoin de garder ces fonctions "virtuelles" car leur implémentation sera différente dans les sous-classes...

Et voici ce que g++ me répond lorsque j'essaie de compiler ça:
./GenericHeader.hpp:36: error: invalid use of ‘virtual’ in template declaration of ‘virtual bool GenericHeader<HeaderType>::set(std::string, Field)’
./GenericHeader.hpp:43: error: invalid use of ‘virtual’ in template declaration of ‘virtual Field GenericHeader<HeaderType>::get(std::string)’


Je ne trouve pas l'erreur, je suis un peu perdu.... :-/
A voir également:

4 réponses

mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 
Le problème c'est qu'une fonction template est sensée être implémentée dans le .hpp. La seule chose que tu peux à mon avis faire c'est juste déclarer la fonction template :
template <typename T> void f();

et l'implémenter plus tard... A noter que le code source de chaque membre de ta classe template doit être implémenté au moment ou tu vas instancier ta classe template. Ca veut dire que tu peux potentiellement implémenter une classe template dans un .cpp mais ce code ne sera disponible que dans ce fichier cpp. Et c'est pour ca qu'en général on met toujours le code d'une fonction template dans le .hpp.

Bonne chance
1
kilian Messages postés 8732 Date d'inscription   Statut Modérateur Dernière intervention   1 526
 
Ah je vois, les templates sont beaucoup plus bordélique que ce que je pensais....
Bon ben je vais les utiliser avec beaucoup plus de parcimonie je crois...

Merci pour ta réponse en tout cas, je comprends mieux.
J'ai d'ailleurs découvert qu'on ne pouvait pas créer de fonction membre modèle et vituelle à la fois:
https://bytes.com/topic/c/answers/60332-template-virtual-member-method-not-allowed-how-bypass
0
Char Snipeur Messages postés 9813 Date d'inscription   Statut Contributeur Dernière intervention   1 299
 
Salut.
Pour info, si tu enleve le virtual, ça compil ?
Je pense que tu peux éventuellement rusé ce que tu veux faire en passant par une fonction friend.
0
kilian Messages postés 8732 Date d'inscription   Statut Modérateur Dernière intervention   1 526
 
Voui sans le Virtual, ça compile...
Je pourrais certainement ruser avec une fonction friend mais ça me ramène au même problème: j'ai besoin d'une fonction get qui retourne une valeur de type variable et une fonction set qui prend un paramètre de type variable.

En fait je vais faire un exemple.

Prenons une petite structure:
struct MaStructure{
    int a;
    std::string b;
    float c;
}


Je crée ensuite une classe héritant de GenericHeader et parametrée avec MaStructure

class MonHeader : public GenericHeader<MaStructure> {};


Du coup dans cette classe, mon attribut content est comme ceci:
union {
			struct MaStructure hdr;
			uint8_t      buf[sizeof(MaStructure)];
}


Et c'est là que les fonctions membres set et get interviennent. Elles vont me permettre de changer les valeurs des membres de ma structure.

Il faudrait par exemple que je puisse faire:
MonHeader h;
h.set("a", 5); //h.hdr.a=5
h.set("b", "une chaine"); //h.hdr.b="une chaine"

std::cout << h.get("a") << h.get("b");


Voilà en gros comment ça se passera dans mon code, sachant que des classes comme MonHeader, il y en aura 4 ou 5.
Je pense que je demande un peu l'impossible en fait... J'essaie de faire un truc élégant mais finalement ça deviendra casse-tête et illisible.
Néanmoins, j'aimerais éviter de faire un accesseur et un mutateur pour chaque membre de ma structure...

Et il y a un autre problème: au final, je ne compe pas faire un programme mais une librarie statique...
Pour le coup je pense que je devrais oublier les templates vu que leur instanciation doit être visible dans les en-têtes c++...

Voilà mes débuts dans le c++ ressemblent un peu à un rubicube... :-)
0