Question

J'ai un motif de type décorateur avec une base qui nécessite un paramètre constructeur. Le décorateur est construit de telle sorte qu'il puisse prendre un nombre arbitraire de composants additionnels comme paramètres de modèle (jusqu'à 3 dans cet exemple).

Malheureusement, je ne vois pas comment lui transmettre le paramètre constructeur de la base lorsque plusieurs add-ons sont spécifiés. Dans l'exemple ci-dessous, CMyClass< AddOn_A > A( 100 ); fonctionne parfaitement, mais CMyClass< AddOn_A, AddOn_B > AB( 100 ); génère une erreur au niveau du constructeur CMyClass.

template< class Base >
class AddOn_A : public Base
{
public: 
    AddOn_A( int x ) : Base( x )
    {
    };

    int AddOne()
    {
        return static_cast< Base* >( this )->DoSomething() + 1;
    };
};

template< class Base >
class AddOn_B : public Base
{
public: 
    AddOn_B( int x ) : Base( x )
    {
    };

    int AddTwo()
    {
        return static_cast< Base* >( this )->DoSomething() + 2;
    };
};

class CBase
{
public:
    explicit CBase( int x ) : x_( x )
    {
    };

    int DoSomething()
    {
        return x_;
    };

private:
    int x_;
};

// define an empty AddOn
template< class > class empty {};

// forward declaration and Add-On defaults
template< template< class > class AddOn1 = empty,
          template< class > class AddOn2 = empty,
          template< class > class AddOn3 = empty >
class CMyClass;

// specialized template for the default case
template<> class CMyClass< empty, empty, empty > {};

// actual definition
template< template< class > class AddOn1,
          template< class > class AddOn2,
          template< class > class AddOn3 >
class CMyClass : public AddOn1< CBase >,
                 public CMyClass< AddOn2, AddOn3 >
{
public:
    // what needs to go here???
    CMyClass( int x ) : AddOn1< CBase >( x )
    {};
};

int _tmain( int argc, _TCHAR* argv[] )
{
    // works
    CMyClass< AddOn_A > A( 100 );
    _ASSERT( A.AddOne() == 101 );

    // works
    CMyClass< AddOn_B > B( 100 );
    _ASSERT( B.AddTwo() == 102 );

    // generates an error at the CMyClass ctor:
    // error C2512: 'CMyClass<AddOn1>' : no appropriate default constructor available
    CMyClass< AddOn_A, AddOn_B > AB( 100 );
    _ASSERT( AB.AddOne() == 101 );
    _ASSERT( AB.AddTwo() == 102 );

    return 0;
}

Si quelqu'un peut dire ce que je peux faire de mal, merci de me le faire savoir.

Merci, PaulH

Était-ce utile?

La solution

Vos erreurs proviennent généralement du fait que CMyClass n'a pas de constructeur par défaut (car vous définissez plutôt un CMyClass(int)), il est donc nécessaire d'instancier explicitement vos parents avec le constructeur x que vous avoir. Ainsi, par exemple, dans votre définition de CMyClass<empty, empty, empty>, vous devez ajouter l'appel à CMyClass<AddOn_A> A(100) dans la liste d'initialisation

.
CMyClass(int x) : AddOn1<CBase>(x), CMyClass<AddOn2, AddOn3>(x) //send x down

Maintenant que nous avons A envoyé CMyClass<AddOn_A, AddOn_B> AB(100) ultérieurement, il est nécessaire que votre spécialisation de cas de base (CMyClass<AddOn_B, empty, empty>) ait maintenant un constructeur qui accepte CMyClass(int x) mais ne fait rien avec elle

template<>
class CMyClass<empty, empty, empty> {
public:
    CMyClass(int) {} //do nothing
};

Le compilateur peut maintenant trouver les constructeurs appropriés et créer vos classes comme vous le souhaitez

Juste pour expliquer pourquoi des lignes comme <=> fonctionnent, c'est parce que <=> (dans cet exemple) n'a qu'un seul parent, <=> et votre spécialisation

.
template<> class CMyClass< empty, empty, empty > {};

a-t-il un constructeur par défaut, car il est vide (ou, plus formellement, car il ne définit aucun autre constructeur). Cela tombe en panne immédiatement une fois que vous appelez <=> parce que cela a deux parents, <=> et <=>. Cependant, le premier n'a pas de constructeur par défaut, le compilateur ne sait donc pas comment construire il. C’est pourquoi nous devons ajouter cette ligne à la liste d’initialisation. Nous demandons donc au compilateur de créer <=> à l’aide de son constructeur <=> (remarque: cela signifie que le compilateur essaiera également de créer <=> avec le paramètre <=> , nous devons donc ajouter un constructeur à cette spécialisation qui acceptera le paramètre).

Autres conseils

  • Ce que vous essayez d’atteindre n’est pas immédiatement clair. J'espère que vous ne confondez pas héritage et modèles.

  • empty, AddOn_A et AddOn_B sont des modèles de classe. Ce ne sont pas des instances d'une classe. Vous devez avoir des classes réelles.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top