C++ Composite Template Class Factory

Is it possible to make a composite template class factory without manually specifying all of the combinations? What I mean is if I have these classes:

class CompositeBase {};

template< typename C1, typename C2, typename C3 >
class Composite : public CompositeBase
{
private:
    C1 component1;
    C2 component2;
    C3 component3;
};

class Component0 {}; //Also have Component1-9

I would like to create a function like this:

CompositeBase *CreateComposite(int c1, int c2, int c3);

so that

CreateComposite(4,3,7);

would create and return a

Composite<Component4,Component3,Component7>

The reason to do this is so that I can load data from a file and create the different composite objects. The file would have the three values for the components to create each composite object, then the other data required by it.

The problem is with 10 different components, there are 1000 different possible composite classes. To specify all of them would require a switch statement for the 1st component, 10 switch statements for the second component within that one, and 100 switch statements for the third component within those ten, and the function would be 1000+ lines long.

Is there any other way to write the CreateComposite function? Other than this:

CompositeBase *CreateComposite(int c1, int c2, int c3)
{
   switch(c1)
   {
   case 0:
       switch( c2 )
       {
       case 0:
           switch( c3 )
           {
              case 0: return new Composite<Component0,Component0,Component0>;
              case 1: return new Composite<Component0,Component0,Component1>;
              //etc
           }
           //etc
       }
       //etc
   }
}

You can avoid O(n^3) complexity to O(n) by using cascade template methods with single switch-case in it:

#include <iostream>
using namespace std;

class CompositeBase
{
public:
    virtual void print( std::ostream& o_out ) = 0;
};

template< typename C1, typename C2, typename C3 >
class Composite : public CompositeBase
{
public:
    void print( std::ostream& o_out )
    {
        o_out << typeid(*this).name();
    }
private:
    C1 component1;
    C2 component2;
    C3 component3;
};


class Component0 {};
class Component1 {};
class Component2 {};
class Component3 {};
class Component4 {};
class Component5 {};
class Component6 {};
class Component7 {};
class Component8 {};
class Component9 {};

template<typename C1,typename C2,typename C3>
CompositeBase *CreateComposite0()
{
    return new Composite<C1,C2,C3>();
}

template<typename C1,typename C2>
CompositeBase *CreateComposite1(int c3)
{
    switch(c3)
    {
    case 0: return CreateComposite0<C1,C2,Component0>();
    case 1: return CreateComposite0<C1,C2,Component1>();
    case 2: return CreateComposite0<C1,C2,Component2>();
    case 3: return CreateComposite0<C1,C2,Component3>();
    case 4: return CreateComposite0<C1,C2,Component4>();
    case 5: return CreateComposite0<C1,C2,Component5>();
    case 6: return CreateComposite0<C1,C2,Component6>();
    case 7: return CreateComposite0<C1,C2,Component7>();
    case 8: return CreateComposite0<C1,C2,Component8>();
    case 9: return CreateComposite0<C1,C2,Component9>();
    default: return 0;
    }
}

template<typename C1>
CompositeBase *CreateComposite2(int c2, int c3)
{
    switch(c2)
    {
    case 0: return CreateComposite1<C1,Component0>(c3);
    case 1: return CreateComposite1<C1,Component1>(c3);
    case 2: return CreateComposite1<C1,Component2>(c3);
    case 3: return CreateComposite1<C1,Component3>(c3);
    case 4: return CreateComposite1<C1,Component4>(c3);
    case 5: return CreateComposite1<C1,Component5>(c3);
    case 6: return CreateComposite1<C1,Component6>(c3);
    case 7: return CreateComposite1<C1,Component7>(c3);
    case 8: return CreateComposite1<C1,Component8>(c3);
    case 9: return CreateComposite1<C1,Component9>(c3);
    default: return 0;
    }
}

CompositeBase *CreateComposite(int c1,int c2, int c3)
{
    switch(c1)
    {
    case 0: return CreateComposite2<Component0>(c2,c3);
    case 1: return CreateComposite2<Component1>(c2,c3);
    case 2: return CreateComposite2<Component2>(c2,c3);
    case 3: return CreateComposite2<Component3>(c2,c3);
    case 4: return CreateComposite2<Component4>(c2,c3);
    case 5: return CreateComposite2<Component5>(c2,c3);
    case 6: return CreateComposite2<Component6>(c2,c3);
    case 7: return CreateComposite2<Component7>(c2,c3);
    case 8: return CreateComposite2<Component8>(c2,c3);
    case 9: return CreateComposite2<Component9>(c2,c3);
    default: return 0;
    }
}

int main()
{
    CompositeBase* base1 = CreateComposite(4,5,6);
    CompositeBase* base2 = CreateComposite(8,2,0);
    base1->print(cout);
    cout << endl;
    base2->print(cout);
    return 0;
}

Just for fun you can use boost proprocessor for O(1) complexity

#include <iostream>
#include <boost/preprocessor/repetition.hpp>
using namespace std;

class CompositeBase
{
public:
    virtual void print( std::ostream& o_out ) = 0;
};

template< typename C1, typename C2, typename C3 >
class Composite : public CompositeBase
{
public:
    void print( std::ostream& o_out )
    {
        o_out << typeid(*this).name();
    }
private:
    C1 component1;
    C2 component2;
    C3 component3;
};

#define DIM 10

#define COMPONENT_DECLARATION(z,n,unused) class BOOST_PP_CAT(Component,n) {};
BOOST_PP_REPEAT(DIM,COMPONENT_DECLARATION, ~)
#undef COMPONENT_DECLARATION

template<typename C1,typename C2,typename C3>
CompositeBase *CreateComposite0()
{
    return new Composite<C1,C2,C3>();
}

template<typename C1,typename C2>
CompositeBase *CreateComposite1(int c3)
{
#define COMPOSITE(z,n,unused) case n: return CreateComposite0<C1,C2,BOOST_PP_CAT(Component,n)>();
    switch(c3)
    {
BOOST_PP_REPEAT(DIM,COMPOSITE,~)
    default: return 0;
    }
#undef COMPOSITE
}

template<typename C1>
CompositeBase *CreateComposite2(int c2, int c3)
{
#define COMPOSITE(z,n,unused) case n: return CreateComposite1<C1,BOOST_PP_CAT(Component,n)>(c3);
    switch(c2)
    {
BOOST_PP_REPEAT(DIM,COMPOSITE,~)
    default: return 0;
    }
#undef COMPOSITE
}

CompositeBase *CreateComposite(int c1,int c2, int c3)
{
#define COMPOSITE(z,n,unused) case n: return CreateComposite2<BOOST_PP_CAT(Component,n)>(c2,c3);
    switch(c1)
    {
BOOST_PP_REPEAT(DIM,COMPOSITE,~)
    default: return 0;
    }
#undef COMPOSITE
}

#undef DIM

int main()
{
    CompositeBase* base1 = CreateComposite(4,5,6);
    CompositeBase* base2 = CreateComposite(8,2,0);
    base1->print(cout);
    cout << endl;
    base2->print(cout);
    return 0;
}

In any case, I'd recommend to avoid these solutions if possible.


Template arguments must be known at compile time. A possible solution would be: CreateComposite<int, int, int>() and you can specialize it for every possible case. Oh, well: that's rather a no go.. I'd suggest that you rather go with some oldfashioned dynamic polymorphism and a std::vector<ComponentBase> .


It is not possible to generate all the possible combinations of a template at runtime. The compiler needs to know which ones you will be using so that it can generate code for them.

Have you considered using composition rather than inheritance?

Edit: By composition I was thinking more along the lines of the following:


class Composite
{
private:
    ComponentBase * component1;
    ComponentBase * component2;
    ComponentBase * component3;
};
class Component0 : public ComponentBase {}; //Also have Component1-9

If you can't use pointers to a base class for some reason, you're stuck having code to generate all the permutations of template classes. But rather than using nested case statements, you can use a table to create new instances, and macros to make the code easier.

typedef CompositeBase * NewComposite();
#define NEW_COMPOSITE(P1,P2,P3) CompositeBase * NewComposite##P1##P2##P3() { return new Composite<Component##P1,Component##P2,Component##P3>; }
NEW_COMPOSITE(0,0,0) NEW_COMPOSITE(0,0,1) NEW_COMPOSITE(0,0,2) NEW_COMPOSITE(0,0,3)
NEW_COMPOSITE(0,0,4) ...
...
CompositeBase *CreateComposite(int c1, int c2, int c3)
{
    static NewComposite * newCompositeTable[10][10][10] = {{{NewComposite000,NewComposite001,...},{NewComposite010,...}}};
    return newCompositeTable[c1][c2][c3]();
}

I can't really say this is a better approach than the one you started with, but it's an alternate to consider.

链接地址: http://www.djcxy.com/p/69064.html

上一篇: 继承自c ++中的模板类

下一篇: C ++复合模板类工厂