9
votes

Le type d'une classe de base peut-il être obtenu à partir d'un type de modèle automatiquement?

J'essaie d'utiliser des modèles méta-programmation pour déterminer la classe de base. Existe-t-il un moyen d'obtenir automatiquement la classe de base sans se spécialiser explicitement pour chaque classe dérivée?

class foo { public: char * Name() { return "foo"; }; };
class bar : public foo { public: char * Name() { return "bar"; }; };

template< typename T > struct ClassInfo { typedef T Base; };
template<> struct ClassInfo<bar> { typedef foo Base; };

int main()
{
  ClassInfo<foo>::Base A;
  ClassInfo<bar>::Base B;

  std::cout << A.Name();  //foo
  std::cout << B.Name();  //foo
}


5 commentaires

Utilisez std :: is_base_of


@iammilind: Ce n'est que pour tester si une classe est la base d'une autre, vous devez connaître la classe de base à tester avec déjà.


De quoi en avez-vous besoin? Je ne pense pas que ce soit possible, mais il y a peut-être une approche différente pour résoudre le problème réel.


Ce n'est pas possible et je me soutiens avec le problème actuel - une connaissance explicite de la classe de base ne devrait généralement pas être nécessaire.


Au fait, la liaison d'une chaîne littéral à Char * est obsolète . Utilisez const char * à la place.


6 Réponses :


5
votes

Je ne suis pas au courant d'un modèle de sélection de la classe de base et je ne suis pas sûr que l'un existe ou c'est même une bonne idée. Il y a beaucoup de façons dont cela brise l'extensibilité et va à l'encontre de l'esprit d'héritage. Lorsque bar code> hérités publiques foo code>, bar code> est un fort> foo code> de tous les objectifs pratiques, et le code client ne doit pas nécessiter de distinguer la classe de base et la classe dérivée.

Un Public Typedef dans la classe de base se gratte souvent les démches que vous pourriez avoir besoin d'avoir rayé et plus clair: p>

class foo { public: typedef foo name_making_type; ... };

int main() {
    Foo::name_making_type a;
    Bar::name_making_type b;
}


2 commentaires

Bon. J'étais sur le point d'écrire ceci.


C'est pour un système de réflexion C ++ très léger. Le code "Client" fait la sérialisation et la messagerie de classe générales avec la déformation minimale possible de et / ou des ajouts à la classe d'origine.



18
votes

Il est possible avec C ++ 11 et DeclType Code>. Pour cela, nous allons exploit qu'un pointeur à un membre n'est pas un pointeur dans la classe dérivée lorsque le membre est hérité d'une classe de base.

Par exemple: P>

struct base2{ void f(){} };

struct not_deducible2 : base, base2{};

int main(){
  decltype(base_of(&not_deducible2::f)) x; // error: 'f' is ambiguous
}


2 commentaires

Merci Xeo, c'est une solution partielle très intéressante et très similaire à ce que je cherche. Je vais examiner ça plus loin


Pouvez-vous étendre votre solution pour accepter également le cas, où 'Base' contient la fonction membre de Const et non Const "F '?



1
votes

Qu'est-ce qu'il y a avec la classe de base ? Êtes-vous un programmeur .NET ou Java?

C ++ prend en charge plusieurs héritages et n'a pas non plus de classe de base courante globale. Ainsi, un type C ++ peut avoir zéro, un ou plusieurs classes de base. L'utilisation de l'article défini est donc contre-indiquée.

Étant donné que la classe de base n'a aucun sens, il n'y a aucun moyen de le trouver.


3 commentaires

Il existe de fortes raisons d'efficacité que Java n'autorise qu'une classe de base et j'ai tendance à restructurer mon code C ++ pour les mêmes raisons - il est donc logique de créer un sous-ensemble utile.


@Vonriphenburger: la question doit alors indiquer: "Pour une classe avec une classe de base immédiate, héritée du public et non-virtuellement, est-il possible de découvrir le type de classe de base?" Et il n'est toujours pas clair si vous recherchez la classe de base immédiate, ou un autre ancêtre. Et Java permettant qu'une seule classe de base n'a rien à voir avec l'efficacité et beaucoup à voir avec la conception de la langue souhaitée pour forcer les codeurs "Le seul chemin véritable à OUP". Idem pour manque de fonctions libres.


J'ai dit pour la première base déclarée. Il semblait évident que la base immédiate était recherchée et non un ancêtre aléatoire, mais cela aurait pu être plus clairement indiqué. UM, merci pour votre contribution, Ben.



5
votes

Mes solutions ne sont pas vraiment automatiques, mais le mieux que je puisse penser.

Solution intrusive C ++ 03 03: p>

class B {};

class A : public B {};

template<class T>
struct TypeInfo;

template<>
struct TypeInfo<A>
{
    typedef B Base;
};


1 commentaires

C'est à peu près exactement ce que je suis venu avec aussi. J'espérais qu'il y avait un truc de modèle hardcore que je n'étais pas au courant de cela pourrait l'extraire .. Je vais probablement utiliser la forme intrusive pour les classes avec contrôle de création complète et la forme non intrusive pour les classes semi-étrangères - Merci



1
votes

Je recherche une résolution portable pour des problèmes similaires pendant des mois. Mais je ne trouve pas encore.

g ++ a __ bases et __ directe_bases . Vous pouvez les envelopper dans une liste de types, puis accéder à l'un de ses éléments, par ex. A std :: tuple avec std :: tuple_element . Voir libstDC ++ 's pour l'usage.

Cependant, ce n'est pas portable. Clang ++ n'a actuellement pas de telle intrinsique.


0 commentaires

1
votes

avec C ++ 11, vous pouvez créer une méthode intrusive pour toujours avoir un membre base_t lorsque votre classe n'hérite qu'à partir d'un parent: xxx

avec Cette classe, vous aurez toujours un parent_t alias, pour appeler les constructeurs parent comme s'il s'agissait de la base constructeurs avec un nom (probablement) plus court et un base_t alias, pour rendre votre classe non consciente du type de type de classe de base s'il est long ou fortement modélisé.

Le parent_t est protégé pour ne pas l'exposer au public. Si vous ne voulez pas que le base_t alias est public, vous pouvez toujours hériter étiqued_base comme protégé ou privé , Aucun besoin de modification de la définition de la classe marquéeded_base .

Cette base doit avoir 0 à l'heure d'exécution ou l'espace aérien car ses méthodes sont en ligne, ne faites rien et n'a aucun attribut.


0 commentaires