Pregunta

Tengo un decorador-como el patrón con una base que se requiere de un parámetro del constructor.El decorador se construye de tal forma que pueden tomar un número arbitrario de componentes de complementos como parámetros de la plantilla (hasta 3 en este ejemplo).

Por desgracia, yo no puedo averiguar cómo pasar de la base del parámetro del constructor cuando más de un add-on se especifica.En el ejemplo siguiente, CMyClass< AddOn_A > A( 100 ); funciona perfectamente, pero CMyClass< AddOn_A, AddOn_B > AB( 100 ); se genera un error en el CMyClass constructor.

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 alguien puede señalar lo que puedo estar haciendo mal, por favor hágamelo saber.

Gracias, PaulH

¿Fue útil?

Solución

Sus errores son por lo general se origina en el hecho de que CMyClass no tiene un constructor por defecto (porque definir un CMyClass(int) en su lugar), por lo que es necesario explícitamente crear instancias de sus padres con el CMyClass(int) constructor que tiene.Así, por ejemplo, en la definición de la CMyClass usted necesita agregar la llamada a CMyClass(int) en la lista de inicializador

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

Ahora que tenemos CMyClass envío x abajo de la línea, es necesario que el caso base de la especialización (CMyClass<empty, empty, empty>) ahora tiene un constructor que acepta x pero no hace nada con ella

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

Ahora el compilador puede encontrar a los constructores y crear sus clases como se esperaba


Sólo para explicar por qué las líneas como CMyClass<AddOn_A> A(100) trabajo, es porque A (en el ejemplo) tiene sólo uno de los padres, CMyClass<empty, empty, empty>, y su especialización

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

¿ tiene un constructor predeterminado, porque es vacía (o, más formalmente, porque no define ningún otro constructores).Esto rompe de inmediato una vez que usted llame CMyClass<AddOn_A, AddOn_B> AB(100) debido a que ha dos los padres, CMyClass<AddOn_B, empty, empty> y CMyClass<empty, empty, empty>, sin embargo , el primero no tiene un constructor predeterminado, por lo que el compilador no sabe cómo construirlo.Por eso debemos añadir que una línea a la lista de inicializador, así que le decimos al compilador para crear CMyClass<AddOn_B, empty, empty> el uso de su CMyClass(int x) constructor (nota cómo que significa que el compilador intentará hacer CMyClass<empty, empty, empty> con el x parámetro, así que tenemos que añadir un constructor para que la especialización de los cuales acepta el parámetro).

Otros consejos

  • No es claro de inmediato de lo que usted está tratando de lograr.Espero que no son la mezcla de la herencia y plantillas.

  • empty, AddOn_A y AddOn_B son plantillas de la clase.No son instancias de una clase.Usted necesita tener clases reales.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top