membre de modèle non statique: possible?

Est-il possible de créer un champ de modèle non statique dans une classe?
Si non, comment résoudre ce problème?

Ces champs doivent être créés au moment de la compilation, selon les besoins.

Exemple

J’ai beaucoup de classe B , comme B1 , B2 , B3 .
(Dans le cas réel, ils ont des noms plus significatifs.)

Je veux créer une classe D dont la fonction de modèle non statique add() qui doit counter++ chaque fois que je l’appelle, pour chaque BX individuel, pour une certaine instance de D.
(Dans le cas réel, cela rend quelque chose de plus complexe.)

Voici une démo de travail pour y parvenir.
Malheureusement, je dois actuellement coder en dur chaque BX , un par un ( B1 , B2 , B3 ) dans D : –

 class B1{};class B2{};class B3{}; class Counter{ public: int counter=0; }; templateclass Tag{}; class D{ Counter countB1; Counter countB2; Counter countB3; public: template void add(){ add_(Tag()); } private: void add_(Tag){ countB1.counter++;} void add_(Tag){ countB2.counter++;} void add_(Tag){ countB3.counter++;} public: template int get(){ return get_(Tag()); } private: int get_(Tag){ return countB1.counter;} int get_(Tag){ return countB2.counter;} int get_(Tag){ return countB3.counter;} }; 

Voici l’usage. Notez que chaque instance de D conserve son propre counter : –

 int main() { D d1; d1.add(); d1.add(); d1.add(); std::cout<<d1.get()<<" "<<d1.get()<<" "<<d1.get()<<"\n"; //^ print 0 2 1 D d2; d2.add(); std::cout<<d2.get()<<" "<<d2.get()<<" "<<d2.get()<<"\n"; //^ print 1 0 0 (not 1 2 1) return 0; } 

Je rêve de quelque chose comme: –

 class D{ Counter countBX; //??? public: template void add(){ Counter::getNonStaticInstance(this).counter++; //??? } public: template int get(){ return Counter::getNonStaticInstance(this).counter; //??? } }; 

Je sais comment faire si countBX est statique, mais pour non-statique, cela semble impossible.

Utilisation de std::map std::unordered_map unordered_map (suggestion de Yakk; merci) des index et RTTI?

 #include  #include  #include  class B1 {}; class B2 {}; class B3 {}; class D { private: std::unordered_map bxMap; public: template  void add () { ++ bxMap[std::type_index(typeid(BX))]; } template  int get () { return bxMap[std::type_index(typeid(BX))]; } }; int main () { D d1; d1.add(); d1.add(); d1.add(); std::cout<()<<" "<()<<" "<()<<"\n"; //^ print 0 2 1 D d2; d2.add(); std::cout<()<<" "<()<<" "<()<<"\n"; //^ print 1 0 0 return 0; } 

Vous n’avez pas besoin de RTTI pour résoudre ce problème, ni de std::map , qui sont très coûteux (spécialement RTTI). Le modèle variadique et l’inheritance peuvent résoudre ce problème pour vous:

 class B1 {}; class B2 {}; class B3 {}; template class Counter { public: int counter = 0; }; template class D : public Counter... { public: template void add() { Counter::counter++; } template int get() { return Counter::counter; } }; 

Ce qui est très proche de ce que vous vouliez réellement (vous étiez dans la bonne voie, au fait).

Malheureusement, tant que nous n’aurons pas réfléchi à la norme, il n’y aura pas de moyen facile de parcourir les membres d’une classe.

Jusque-là, les solutions impliquent de mettre en œuvre la reflection vous-même (avec force et utilisent souvent des macros qui présentent leurs propres problèmes, comme la débogage), ou d’envelopper vos types dans un autre type (plus facile).

Nous pouvons faire cela avec une classe de base qui a un std::array of Counters, un pour chaque BX :

 template struct Base { std::array counters; // ... more on this later }; 

Ensuite, notre classe D peut en tirer et obtenir les compteurs dont elle a besoin:

 struct D : Base{ /*...*/}; 

Nous allons ensuite implémenter une fonction IndexOf dans la classe de base qui nous permettra de transformer un type (un de B1 B2 B3 ) en un index.

Nous pouvons le faire avec des caractères de type et des expressions de pli:

 template static constexpr int IndexOf() { // find index of T in Bs... int toReturn = 0; int index = 0; (..., (std::is_same_v ? toReturn = index : ++index)); return toReturn; } 

Et maintenant, notre classe D est beaucoup simplifiée et ne repose pas sur l’envoi de balises:

 struct D : Base{ template void add(){ counters[IndexOf()].counter++; } template int get(){ return counters[IndexOf()].counter;; } }; 

Démo en direct


MODIFIER:

Version C ++ 14 d’ IndexOf :

 template static constexpr int IndexOf() { // find index of T in Bs... int toReturn = 0; int index = 0; using swallow = int[]; (void) swallow {0, (std::is_same() ? toReturn = index : ++index, 0)...}; return toReturn; } 

Démo C ++ 14