2011-06-15 3 views
16

J'essaie de définir une construction récursive comme une tâche agricole. Ici, j'essaie de trouver deux opérandes qui peuvent fonctionner récursivement pour n'importe quel nombre d'opérandes car il peut s'emboîter lui-même.Détection automatique C++ des arguments de modèle?

template <typename T1, typename T2> 
class Farm 
{ 
    private: 
    T1 *task1; 
    T2 *task2; 
    public: 
    // save them so that I can use them when invoking call operator 
    Farm(T1 *_t1, T2 *_t2): task1(_t1), task2(_t2) { } 

    void operator()() 
    { 
     // invoke call operator, meaning a farm could be a task (arbitrary nesting) 
     (*task1)(); 
     (*task2)(); 
    } 
}; 
int main() 
{ 
    ... create two pointer(A *a, B *b...) 
    Farm(a,b); // error: missing template arguments before ‘(’ token 

    Farm<A, B>(a,b); // in this works, it works 
} 

Le problème est avec l'auto-détection des arguments de modèle qui ne fonctionne pas dans ce cas. Qu'est-ce que je fais mal et comment pourrais-je réaliser ce paramètre de paramètres de détection implicite par le compilateur gcc.

Merci!

Répondre

16

Les classes/constructeurs ne détectent pas automatiquement les types comme les fonctions. Vous devez écrire une fonction wrapper pour créer votre classe.

Ceci est fait comme suit et appelé le modèle Object Generator. (Merci @Itjax!)

template <typename T1, typename T2> 
Farm<T1, T2> makeFarm(T1* a, T2* b) { 
     return Farm<T1,T2>(a,b); 
} 

// silly example 
Farm<T1,T2> farm = makeFarm(a,b); 

// better example 
template<typename T> 
void plow(T& farm) { farm.applyTractor(...); } 

void blah() { 
    plow(makeFarm(b,a)) 
} 

Ce modèle émerge beaucoup lors de l'utilisation lambda/bind/foreach et des pièces similaires, lorsque vous voulez créer un objet temporaire d'une classe avec des arguments basé sur un modèle et éviter de spécifier leur type , généralement en l'envoyant dans une autre fonction modèle (std::for_each) ou un objet polymorphe (std::function).

Remarque: La fonction génératrice généralement intégrée et avec l'optimisation de l'élision de la copie, il n'y aura probablement aucun constructeur de copie appelé dans votre code. Si vous ne pouvez pas copier votre objet, makeFarm() devrait retourner un pointeur intelligent à la place (std::unique_ptr est préféré dans C++ moderne).

+3

Exactement. C'est ce qu'on appelle le langage Object Generator: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Object_Generator – ltjax

+0

Merci beaucoup pour votre réponse! Mais pourriez-vous me dire comment je peux mettre cette _Farm_ à l'échelle pour travailler avec des arguments arbitraires (en utilisant des templates variadiques C++ 0x et éventuellement des tuples). J'ai lu beaucoup et essaye de le faire mais n'ai pas pu trouver une solution. – usman

+0

@ user600029: C'est une question différente. Veuillez le rechercher (ou postez une nouvelle question). Personnellement, je n'ai pas assez utilisé C++ 0x pour vous aider, mais je suis sûr qu'il y en a beaucoup d'autres ici qui savent comment le faire correctement. – Macke

4

La solution de contournement habituelle consiste à fournir une fonction de modèle qui renvoie l'implémentation réelle. La bibliothèque C++ standard utilise cet alot, par ex. avec std :: make_pair.

Exemple:

template<typename T> 
struct foo_t { 
    ... 
}; 

template<typename T> 
foo_t<T> foo(T const &f) { 
    return foo_t<T>(f); 
} 

Cela fonctionne parce que pour les fonctions du compilateur est autorisé à déduire les typenames de la liste des paramètres.

1

Vous pouvez ajouter une classe de base pour la Ferme de classe:

class FarmBase 
{ 
    public: 
    virtual ~FarmBase(){} 

    virtual void operator()() = 0; 
}; 


template <typename T1, typename T2> 
class Farm : public FramBase 
{ 
    private: 
    T1 *task1; 
    T2 *task2; 
    public: 
    // save them so that I can use them when invoking call operator 
    Farm(T1 *_t1, T2 *_t2): task1(_t1), task2(_t2) { } 
    virtual ~Farm(){} 

    virtual void operator()() 
    { 
     // invoke call operator, meaning a farm could be a task (arbitrary nesting) 
     (*task1)(); 
     (*task2)(); 
    } 
}; 
template< typename A, typename B > 
FarmBase* Create(A *a, B *b) 
{ 
    return new Farm< A, B >(a, b); 
} 

alors les principaux ressemble à:

int main() 
{ 
    //... create two pointer(A *a, B *b...) 

    FarmBase *fobj = CreateFarm(a, b); 
} 
+0

Comment l'aide automatique en C++ 0x? Juste curieux. – Macke

+1

@Macke enlevé le non-sens –

Questions connexes