2009-11-11 60 views
2

是否可以在不手动指定所有组合的情况下制作复合模板类工厂?我的意思是,如果我有这些类:C++复合模板类工厂

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 

我想创建这样一个功能:

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

使

CreateComposite(4,3,7); 

将创建并返回一个

Composite<Component4,Component3,Component7> 

这样做的理由是以便我可以从文件加载数据并创建不同的组合对象。该文件将具有用于创建每个复合对象的组件的三个值,然后是其所需的其他数据。

问题是有10个不同的组件,有1000个不同的可能组合类。要指定所有这些,将需要第一个组件的switch语句,第二个组件的10个switch语句以及这10个内的第三个组件的100个switch语句,并且该函数的长度为1000+行。

是否有任何其他方式来编写CreateComposite函数?除此之外:

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

回答

2

您可以使用它与单一的switch-case级联模板方法避免为O(n^3)复杂度为O(n):

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

只是为了好玩,你可以使用boost proprocessor为O(1 )复杂性

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

无论如何,我建议尽可能避免这些解决方案。

0

不是。这需要C++没有的反射。

为什么不只是CreateComposite<T1, T2, T3>()

编辑:听起来像一个情况下,国家/战略模式会有所帮助。

+0

我需要从文件中读取这些数据,所以我不能这样称呼它。 – Frank 2009-11-11 18:08:11

3

在运行时无法生成模板的所有可能组合。编译器需要知道你将使用哪一个,以便它可以为它们生成代码。

你考虑过使用composition而不是继承吗?

编辑:通过组成我的线沿线的思路更加如下:


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

如果你不能使用指针的基类出于某种原因,你坚持有代码生成模板类的所有排列。但不是使用嵌套的case语句,你可以使用表来创建新的实例和宏,以使代码更容易。

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](); 
} 

我真的不能说这是一个比你开始的更好的方法,但它是一个替代考虑。

+0

我更新了帖子。我正在使用作文,至少我认为是这样。只是Composite的组件是由模板参数指定的。 – Frank 2009-11-11 18:06:38

3

在编译时必须知道模板参数。一种可能的解决方案是: CreateComposite<int, int, int>(),您可以针对每种可能的情况对其进行专门化。哦,那么:这是一个没有去.. 我建议你宁愿去与一些老式的动态多态性和std::vector<ComponentBase>

+1

+ 1,000,000为提出唯一的合理解决方案,只需使用多态! – 2009-11-11 18:39:49

+0

嗯,就是这样。我在编译时知道所有可能的参数,它们只能是Component0-9。例如永远不会有Composite 。我添加了一个工作但长的CreateComposite函数的例子。它似乎应该有一些方法来做到这一点,而不是所有的打字。 我可能不得不做你的建议,它似乎是一个很好的方式来创建复合,而不需要单独分配组件,也不必使用虚拟功能来访问它们。 – Frank 2009-11-11 18:39:53

+0

你在编译时知道可能的参数,但不是 - 实际参数;它们在运行时通过3个整数参数进入,这对于从中生成模板来说已经太晚了。 – Kylotan 2009-11-12 11:08:19

0

虽然我同意其他人的观点,动态多态性可能是最好的选择,但从技术上讲,你可以做你正在问的问题。其他人,现在避免你的眼睛...:

#include <stdexcept> 
#include <iostream> 

struct CompositeBase 
{ 
    virtual ~CompositeBase() = 0 {} 
    virtual std::ostream& output (std::ostream& os) const = 0; 
}; 

template<typename CA, typename CB, typename CC> 
struct Composite : public CompositeBase 
{ 
    std::ostream& output (std::ostream& os) const 
    { 
     return os << componentA.id() << "," << componentB.id() << "," << componentC.id(); 
    } 

    CA componentA; 
    CB componentB; 
    CC componentC; 
}; 

struct Component0 {int id() const {return 0;}}; 
struct Component1 {int id() const {return 1;}}; 
struct Component2 {int id() const {return 2;}}; 
struct Component3 {int id() const {return 3;}}; 
struct Component4 {int id() const {return 4;}}; 
// ... 

template<int N> struct IntToType {}; 
template<> struct IntToType<0> {typedef Component0 Type;}; 
template<> struct IntToType<1> {typedef Component1 Type;}; 
template<> struct IntToType<2> {typedef Component2 Type;}; 
template<> struct IntToType<3> {typedef Component3 Type;}; 
template<> struct IntToType<4> {typedef Component4 Type;}; 
// ... 

// Change 4 to match number of composites. 
template<int N1 = 4, int N2 = 4, int N3 = 4> 
struct CompositeFactory 
{ 
    static CompositeBase* create (int c1, int c2, int c3) 
    { 
     if (c1 == N1) 
     { 
      if (c2 == N2) 
      { 
       if (c3 == N3) 
        return new Composite<IntToType<N1>::Type, IntToType<N2>::Type, IntToType<N3>::Type>; 
       else 
        return CompositeFactory<N1, N2, N3-1>::create (c1, c2, c3); 
      } 
      else 
       return CompositeFactory<N1, N2-1, N3>::create (c1, c2, c3); 
     } 
     else 
      return CompositeFactory<N1-1, N2, N3>::create (c1, c2, c3); 
    } 
}; 

template<int N2, int N3> 
struct CompositeFactory<-1, N2, N3> 
{ 
    static CompositeBase* create (int c1, int c2, int c3) 
    { 
     throw std::runtime_error ("Could not create Composite"); 
    } 
}; 

template<int N1, int N3> 
struct CompositeFactory<N1, -1, N3> 
{ 
    static CompositeBase* create (int c1, int c2, int c3) 
    { 
     throw std::runtime_error ("Could not create Composite"); 
    } 
}; 

template<int N1, int N2> 
struct CompositeFactory<N1, N2, -1> 
{ 
    static CompositeBase* create (int c1, int c2, int c3) 
    { 
     throw std::runtime_error ("Could not create Composite"); 
    } 
}; 

CompositeBase* createComposite (int c1, int c2, int c3) 
{ 
    return CompositeFactory<>::create (c1, c2, c3); 
} 

int main (int argc, char* argv[]) 
{ 
    CompositeBase* comp = createComposite (4,1,2); 

    comp->output (std::cout); 

    return 0; 
} 

这适用于5种,它应该是显而易见的是如何把它扩大到10种。

我不确定我是否真的想要实际使用它 - 对于10个组合体,编译器会生成所有1000个组合模板的实例。

0

为什么你甚至想要一个具有3个完全任意类型成员的泛型复合类?我无法想象你可以在这种情况下为这样的课程编写任何有用的代码。 Composite本身不能包含任何有用的代码,任何使用组合的代码都需要知道其中的类型(您目前没有存储在哪里)。但是,如果3种类型都实现某种已知的接口 - 例如,第一个总是一个数字类型,第二个是序列类型等 - 然后你可以为每个类型使用一个工厂,并使用多态性返回正确的接口,并且根本不需要模板。