2010-09-08 20 views
3

** J'ai eu quelques suggestions pour faire ma pure fonction générique, qui fonctionnerait, mais je préférez limiter la fonction pour n'accepter que Base et ses enfants.Passant sous-classes de modèle de classe variadique pour fonction qui accepte uniquement la classe de base (par déduction paquet paramètre/inférence)

de la difficulté à faire une fonction qui peut accepter des arguments d'un type de base de classe modèle variadique, tandis que la fonction sera effectivement appelée avec les classes qui dérivent de la base. J'ai essayé quelques petites choses. Voici l'idée générale. Compte tenu:

template<typename... Args> struct Base { 
    std::tuple<Args...> data; 
    ... //other stuff 
}; 

struct DerivedA : Base<string, int> { 
}; 

struct DerviedB : Base<bool, string, int> { 
}; 

Quelle est la bonne façon de créer une fonction qui fait cela:

string moosh_together(Base A, Base B) { //I only need access to Base's members 
    return get<0>(A.data) + get<1>(B.data); 
} 

main() { 
    DerivedA aThing; 
     get<0>(aThing.data) = "foo"; 
    DerivedB bThing; 
     get<1>(bThing.data) = "bar'd"; 
    cout << moosh_together(aThing, bThing) << endl; 
} 

Sortie:

foobar'd 

J'ai essayé quelques variations de la fonction moosh_together, aucun de quel travail. Le laisser comme ci-dessus génère une erreur de compilateur sur les arguments de modèle manquants. Je ne sais pas comment passer à la fonction les arguments de modèle qui définissent DerivedA et DerivedB.

Autres choses que j'ai essayé (méthode de fusil de chasse):

string moosh_together(Base<> A, Base<> B) {} 
//err: conversion from 'DerivedA' to non-scalar type 'Base<>' requested 

template<Base<typename... Args> T1, Base<typename... Args> T2> 
string moosh_together(T1 A, T2 B) {} 
//err: expected paramter pack before '...' 

template<Base<Args...> T1, Base<Args...> T2> 
string moosh_together(T1 A, T2 B) {} 
//err: 'Args' was not declared in this scope 
+4

Bordel ce titre me fait mal à la tête. –

+1

Il y a un polymorphisme d'exécution à l'ancienne caché quelque part. Cela ne justifierait-il pas de ne pas faire passer des choses par exemplaire? – sbi

+0

@Zachary Yates Lol, ce qui est pire est que je ne sais pas si ce titre si verbeux à cause de mon manque de complexité C de la connaissance ou réelle du problème que je suis face à –

Répondre

4

Edit:

Si vous avez besoin des deux packs de paramètres, vous pouvez simplement mettre à la fois dans la spécification du modèle:

template<typename... ArgsA, typename... ArgsB> 
string moosh_together(const Base<ArgsA...>& A, const Base<ArgsB...>& B) { 
    return get<0>(A.data) + get<1>(B.data); 
} 

Cela fonctionne parce que les paquets de paramètres sont déduits des arguments et non spécifiés dans une liste. Naturellement, vous ne pouvez pas avoir une classe qui dépend de plusieurs packs de paramètres.

+0

Le premier nécessiterait que les deux instanciations 'Base' aient les mêmes paramètres de template, je pense. Je ne suis pas sûr de savoir comment obtenir deux paramètres de modèles variadiques pour permettre deux bases différentes. – GManNickG

+0

@GMan: Je l'ai maintenant testé. –

+0

Purdy @ Jon: Voir les modifications de code que j'ai fait dans mon code exemple ... Je pense qu'ils rendent votre première solution infaisable, mais vous et GMan ont tous deux mentionné pur générique ... –

1

ne pouvait pas vous créer une classe de base dans la hiérarchie d'héritage pour Base et passer à la fonction que moosh_together()? (Faible connaissance de C++ ici)

+1

Oui, mais j'ai besoin de quelque chose qui gérera une Base avec des membres qui dépendent des paramètres de modèle passés à Base. –

+0

Donc, si le template de base a une arité indéfinie et que vous voulez écrire une fonction qui prend le template sans paramètres de type mais dépend des paramètres de type, comment référenceriez-vous les types des membres de Base? Dans votre définition du problème, ils ne peuvent pas être définis au moment de la compilation. –

+0

Wow, ce commentaire m'a fait mal à la tête aussi. –

2

Lorsque vous écrivez: string moosh_together(Base A, Base B), demandez-vous ce que Base est. Base est un modèle de classe , pas un type de classe.

En d'autres termes, étant donné:

template <typename T> 
struct foo {}; 

foo<int> et foo<float> sont deux types totalement différents, qui vient de advint être fabriqués à partir du même modèle de classe. Ils ont pas de classe de base commune, et vous ne pouvez pas les consulter simplement foo plus que vous pouvez vous référer à la fois int et float avec un seul type.

Vous pouvez factoriser les parties non dépendantes de Base:

struct Core 
{ 
    string name; 
}; 

template <typename... Args> 
struct Base : Core 
{ 
    // ... 
}; 

Et puis reportez-vous aux Core parties:

// pass by reference, to avoid unnecessary copying 
string moosh_together(const Core& a, const Core& b); 

Ou tout simplement faire fonctionner totalement générique:

template <typename BaseOne, typename BaseTwo> 
string moosh_together(const BaseOne& a, const BaseTwo& b); 

Et dire « si vous avez les membres nécessaires, vous pouvez utiliser cette fonction ".

+0

Eh bien, d'accord, l'affacturage des membres non dépendants fonctionne dans cet exemple spécifique. Say DerivedA et DerivedB dépendent tous deux d'un membre de Base qui dépend lui-même des paramètres de modèle transmis à Base? Je suis vraiment à la recherche d'une solution capable de gérer les membres dépendants. Désolé, j'aurais dû utiliser un meilleur exemple. Je vais changer le code. –

+0

sbi m'a corrigé sur mon libellé "template class"/"template template", dont je me rends compte maintenant ce que tu faisais au début de ta réponse. J'avais glacé cette partie et je cherchais juste à éliminer les membres non dépendants. Merci pour la clarification. –

1

Je pense que l'expansion générale de c'est

string moosh_together(Base<T1...> A1, Base<T2...> A2, ... Base<Tn...> An) { 
    return get<0>(A1.data) + get<1>(A2) + ... + get<n-1>(An.data); 
} 

Cela pourrait s'écrire

template<int I> 
string moosh_together() { return ""; } 

template<int I, typename ...Base1Ty, typename ... Bases> 
string moosh_together(Base<Base1Ty...> const& base1, Bases const&... bases) { 
    return get<I>(base1.data) + moosh_together<I+1>(bases...); 
} 

template<typename ... Bases> 
string moosh_together(Bases const&... bases) { 
    return moosh_together<0>(bases...); 
}