2010-07-31 34 views
3

J'ai récemment abordé the constructor problem, où diverses classes mixins qui se décorent (et une classe hôte supérieure) ont des signatures de constructeurs différentes. Pour conserver un seul constructeur dans la classe décorée résultante, et sans ajouter de fonctions init, j'ai trouvé la solution suivante. La seule restriction qu'il place sur une classe mixin est que si son constructeur prend plus d'un paramètre, ils doivent tous être encapsulés dans un seul tuple. (Ce code avec Compiler g ++ nécessite les -std = C++ 0x drapeaux)Résoudre le problème de constructeur mixin en C++ en utilisant des modèles variadiques

#include <boost/tuple/tuple.hpp> 

// Base class for all mixins 
struct Host { 
    float f_; 
    int i_; 

    Host(float f, int i) : f_(f), i_(i) {} 
}; 

// First mixin--constructs with 1 parameter 
template <class B> 
struct M1 : public B { 
    char c_; 

    template <class... A> 
    M1(char c, const A&... a) : B(a...), c_(c) {} 
}; 

// Second mixin--constructs with 3 parameters 
template <class B> 
struct M2 : public B { 
    double d_; 
    short s_; 
    const char* p_; 

    template <class... A> 
    M2(boost::tuple<const char*, double, short> t, const A&... a) 
    : B(a...), p_(t.get<0>()), d_(t.get<1>()), s_(t.get<2>()) {} 
}; 


int main() { 
    // ctor parameters go in this order, from most derived to base: 
    M2<M1<Host>> tst(boost::make_tuple("test", 46.1, (short)-1), (char)5, 4.2f, 2); 
    return 0; 
} 

Mes questions sont les suivantes:
1) Y at-il une meilleure façon plus élégante de résoudre ce problème avec C++ 0X?
2) Plus précisément, les tuples sont-ils vraiment nécessaires?

Répondre

3

Vous n'avez besoin de quelque chose comme des tuples si vous avez plusieurs constructeurs avec une arité différente pour les mixins (et donc des ambiguïtés).

Sinon, vous pouvez simplement gérer les paramètres du mixin comme d'habitude:

template <class... A> 
M2(const char* p, double d, short s, const A&... a) 
    : B(a...), p_(p), d_(d), s_(s) {} 
+0

C'est vrai, mais j'essayais d'aborder le cas le plus général, en imposant aussi peu de restrictions sur les futurs mixins que possible. Dans mon cas, l'arité varie en effet. – Eitan

+0

@eit: Vous voulez dire que vous devez avoir plusieurs constructeurs avec des arités différentes dans un mixin? Ce serait le seul cas problématique auquel je puisse penser. En dehors de cela, je ne vois pas comment cela pourrait être fait plus élégamment. –

+0

Peut-être que je n'étais pas clair. Chaque mixin nécessite seulement un constructeur, mais peut prendre un autre différent. d'args d'autres mixins, comme dans l'exemple. – Eitan

0

Vous pouvez construire la structure de base et le transmettre en tant que paramètre constructeur de M1 et M2, donc ils peuvent appeler un constructeur de copie de b:

M2(const B &b, ....) : B(b), .... 

Êtes-vous vraiment sûr besoin d'héritage? La composition est plus élégante et maintenable.

+0

Vous avez raison sur l'utilisation des constructeurs de copie comme une alternative (un peu inutile si). C++ n'a pas de façon intégrée d'ajouter des mixins, et l'utilisation de CRTP comme dans cet exemple est une solution de contournement commune. Obtenir des fonctionnalités similaires à cet exemple avec la composition signifierait que je devrais définir D2 pour avoir un membre D1-typé, et D1 pour avoir un membre Hôte. C'est plus laid (dans mon opionion), mais plus important encore, cela augmente le couplage. Les mixins ne sont plus indépendants les uns des autres, comme les décorateurs devraient l'être. Avec la structure actuelle, je peux avoir à la fois M1 > et M1 . Avec Composition, je ne peux pas. – Eitan