Pergunta

Eu tenho um decorador-como padrão com uma base que requer um parâmetro de construtor. O decorador é construído de tal modo que ele pode ter um número arbitrário de componentes adicionais como parâmetros de modelo (até três neste exemplo).

Infelizmente, eu não posso descobrir como passar parâmetro de construtor da base para que quando mais de um add-on é especificado. No exemplo abaixo, CMyClass< AddOn_A > A( 100 ); funciona perfeitamente, mas CMyClass< AddOn_A, AddOn_B > AB( 100 ); gera um erro no construtor 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;
}

Se alguém pode apontar o que eu possa estar fazendo de errado, por favor me avise.

Obrigado, PaulH

Foi útil?

Solução

Seus erros são geralmente proveniente do fato de que CMyClass não tem um construtor padrão (porque você definir um CMyClass(int) vez), por isso é necessário para instanciar explicitamente seus pais com o construtor CMyClass(int) que você tem. Assim, por exemplo, na sua definição de CMyClass você precisa adicionar a chamada para CMyClass(int) na lista inicializador

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

Agora que temos CMyClass envio x para baixo da linha, é necessário para o seu caso base especialização (CMyClass<empty, empty, empty>) agora tem um construtor que aceita x mas não faz nada com ele

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

Agora, o compilador pode encontrar os construtores certas e criar suas classes como você espera


Apenas para explicar por que linhas como trabalho CMyClass<AddOn_A> A(100), é porque A (nesse exemplo) tem apenas um dos pais, CMyClass<empty, empty, empty>, e sua especialização

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

faz ter um construtor padrão, porque ele está vazio (ou, mais formalmente, porque não define outros construtores). Isso quebra imediatamente, uma vez que você chama CMyClass<AddOn_A, AddOn_B> AB(100) porque que tem dois pais, CMyClass<AddOn_B, empty, empty> e CMyClass<empty, empty, empty>, porém o primeiro não tem um construtor padrão, de modo que o compilador não sabe como construí-lo. É por isso que é preciso acrescentar que uma linha para a lista de inicializadores, para que dizer ao compilador para criar CMyClass<AddOn_B, empty, empty> usando seu construtor CMyClass(int x) (note como isso significa que o compilador também vai tentar fazer CMyClass<empty, empty, empty> com o parâmetro x, então precisamos adicionar um construtor para que a especialização que vai aceitar o parâmetro).

Outras dicas

  • Não é imediatamente claro o que você está tentando alcançar. Espero que você não está misturando-se herança e modelos.

  • empty, AddOn_A e AddOn_B são modelos de classe. Eles não são instâncias de uma classe. Você precisa ter aulas reais.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top