Frage

Ich habe einen Dekorateur artiges Muster mit einer Basis, die einen Konstruktor Parameter erfordert. Der Dekorateur ist so aufgebaut, dass es eine beliebige Anzahl von Zusatzkomponenten als Template-Parameter nehmen kann (bis zu 3 in diesem Beispiel).

Leider kann ich nicht herausfinden, wie die Basis des Konstruktorparameter zu übergeben, wenn mehr als ein Add-on angegeben ist. Im Beispiel unten funktioniert CMyClass< AddOn_A > A( 100 ); perfekt, aber CMyClass< AddOn_A, AddOn_B > AB( 100 ); erzeugt einen Fehler am CMyClass Konstruktor.

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;
}

Wenn jemand kann darauf hinweisen, was ich falsch gemacht werden kann, lassen Sie es mich wissen.

Danke, PaulH

War es hilfreich?

Lösung

Ihre Fehler entstehen, werden im Allgemeinen aus der Tatsache, dass CMyClass keinen Default-Konstruktor hat (weil Sie einen CMyClass(int) stattdessen definieren), so ist es notwendig, explizit Ihre Eltern mit dem CMyClass(int) Konstruktor instanziiert, die Sie haben. So zum Beispiel in Ihrer Definition von CMyClass müssen Sie den Anruf hinzuzufügen, in der Initialisiererliste CMyClass(int)

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

Nun, da wir CMyClass auf der ganzen Linie x haben zu senden, ist es notwendig, für die Base-Case-Spezialisierung (CMyClass<empty, empty, empty>) nun einen Konstruktor, der x akzeptiert, aber tut nichts damit

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

Nun kann der Compiler die richtigen Konstrukteure finden und Ihre Klassen erstellen, wie Sie erwarten,


Nur um zu erklären, warum Zeilen wie CMyClass<AddOn_A> A(100) Arbeit, es ist, weil A (in diesem Beispiel) hat nur einen Elternteil, CMyClass<empty, empty, empty> und Ihre Spezialisierung

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

hat hat einen Default-Konstruktor, weil es leer ist (oder, formal, weil es keine andere Konstrukteuren definiert). Diese gliedern sich sofort, sobald Sie CMyClass<AddOn_A, AddOn_B> AB(100) nennen, denn das hat zwei Eltern, CMyClass<AddOn_B, empty, empty> und CMyClass<empty, empty, empty>, aber der ehemalige keinen Standardkonstruktor haben, so dass der Compiler nicht weiß, wie es zu konstruieren. Deshalb haben wir, dass eine Zeile in die Initialisiererliste hinzufügen müssen, so dass wir sagen dem Compiler CMyClass<AddOn_B, empty, empty> mit seinem CMyClass(int x) Konstruktor erstellen (beachten Sie, wie das heißt, der Compiler wird auch versuchen, CMyClass<empty, empty, empty> mit dem x Parameter zu machen, also müssen wir einen Konstruktor hinzufügen auf diese Spezialisierung die die Parameter) akzeptiert.

Andere Tipps

  • Es ist nicht sofort klar, was Sie erreichen wollen. Ich hoffe, Sie sind nicht Vererbung und Vorlagen vermischen.

  • empty, AddOn_A und AddOn_B sind Klasse-Vorlagen. Sie sind nicht die Instanzen einer Klasse. Sie müssen tatsächliche Klassen haben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top