【问题标题】:derive from an arbitrary number of classes从任意数量的类派生
【发布时间】:2009-10-20 21:41:34
【问题描述】:

我有一个类,我希望它的功能依赖于一组插件策略。但是,我不确定如何让一个类派生自任意数量的类。

下面的代码是我想要实现的示例。

// insert clever boost or template trickery here
template< class ListOfPolicies >
class CMyClass : public ListOfPolicies 
{
public:
    CMyClass()
    {
        // identifiers should be the result of OR-ing all 
        // of the MY_IDENTIFIERS in the TypeList.
        DWORD identifiers; 

        DoSomeInitialization( ..., identifiers, ... );
    }

    int MyFunction()
    {
        return 100;
    }

    // ...
};

template< class T >
class PolicyA
{
public:
    enum { MY_IDENTIFIER = 0x00000001 };

    int DoSomethingA()
    {
        T* pT = static_cast< T* >( this );
        return pT->MyFunction() + 1;
    };

    // ...
};

template< class T >
class PolicyB
{
public:
    enum { MY_IDENTIFIER = 0x00000010 };

    int DoSomethingB()
    {
        T* pT = static_cast< T* >( this );
        return pT->MyFunction() + 2;
    };

    // ...
};

int _tmain(int argc, _TCHAR* argv[])
{
    CMyClass< PolicyA > A;
    assert( A.DoSomethingA() == 101 );

    CMyClass< PolicyA, PolicyB > AB
    assert( AB.DoSomethingA() == 101 );
    assert( AB.DoSomethingB() == 102 );

    return 0;
}

谢谢, 保罗H

【问题讨论】:

  • 为什么你的示例方法不起作用?
  • 它可能会起作用。我只是不知道如何实现我提到的部分。
  • 如果听起来您正在重新实现 COM 的功能。为什么不使用 COM?
  • 哦,你在找什么我认为是可变参数模板,在 C++0X 中引入
  • @Jherico 我在 COM 中涉猎过一点,但我想不出其中有什么可以实现这一点。你能举个有用的例子吗?

标签: c++ templates multiple-inheritance


【解决方案1】:

使用Boost.MPL 库:

//Warning: Untested
namespace bmpl = boost::mpl;
template<class Typelist>
class X : bmpl::inherit_linearly<Typelist, bmpl::inherit<bmpl::_1, bmpl::_2> >::type
{
...
};

用作:

X<bmpl::vector<Foo, Bar, Baz> > FooBarBaz;

对于“OR-ing all MY_IDENTIFIER”部分,大致如下:

//Warning: still not tested:
enum {OR_ED_IDENTIFIERS = 
    bmpl::fold<Typelist, bmpl::int_<0>, bmpl::bitor_<_1, _2> >::value;
}

【讨论】:

  • 在我为上面示例中的两个策略创建 bmpl::vector 之前,它一直有效。它们都是模板,所以我收到如下错误:“错误 C3203: 'PolicyA' : unspecialized class template can't be used as a template argument for template parameter 'T0', expected a real type”
  • 无论如何,您不能直接从单个策略模板继承,基类始终需要是类。不是内置类型,不是函数,也不是模板。类模板的实例化是一个类,所以这是可以接受的。
  • @PaulH:我错过了这样一个事实,即在您的帖子中,策略不是类,而是模板。作为 MSalters cmets,您不能让类继承自模板。
  • 那听起来像是我的回答。谢谢大家。
【解决方案2】:

要从任意类型的列表派生,您必须列出任意数量的类型。为此,我只知道类型列表。我将在以下代码中使用它:

class nil {};

template< typename H, class T >
struct type_list {
    typedef H head_type;
    typedef T tail_type;
};

鉴于此,您可以创建一个派生自类型列表中所有类型的模板:

template< class TL >
struct derivator;

template<>
struct derivator<nil> {};

template< typename H, typename T >
struct derivator< type_list<H,T> > : public H
                                   , public derivator<T> {};

我用以下代码对此进行了测试

class A {};   void a(A) {std::cout << "A\n";}
class B {};   void b(B) {std::cout << "B\n";}
class C {};   void c(C) {std::cout << "C\n";}

class X : public derivator< type_list<A 
                          , type_list<B 
                          , type_list<C 
                          , nil > > > > {};

int main(void)
{
    X x;
    a(x);
    b(x);
    c(x);

    return 0;
}

VC 和 Comeau 似乎都喜欢这段代码,它会打印出来

A
B
C

所以它似乎工作。

【讨论】:

  • 我并不是要通过代码顶部的注释来暗示我已经接受了类型列表的概念。我对任何事情都持开放态度。我将为您的示例假设这些定义: class CNil {};模板 struct type_list { typedef T THead; typedef U TTail; };不过,我仍然不知道我是如何实际使用它的。如果我这样做: void _tmain(int argc, _TCHAR* argv[]) { CMyClass> AB;然后我在你的“struct derivator<...>”定义中得到一个“error C2504: 'derivator' : base class undefined”。
  • @PaulH:除了列出任意数量的类型的类型列表之外,我没有看到任何其他方法。 :)我粘贴的代码只是为了让你继续前进,我不知道它是否会编译。我会检查一下并用几分钟后编译的东西替换它。
  • +1,这就是我要写的。我相信这是 Andrei Alexandrescu 在现代 C++ 设计中作为 Loki::GenScatterHierarchy. 提出的模式
  • @Kaz:我可能从他那里学到了这一点。很多年前看过的书,这里没有,所以不知道是不是用了同样的技术。
【解决方案3】:

使用类型列表的可能实现:

#include <cstdlib>

/**
 * Base classes that you want to inherit from.
 */
struct A
{
    A() {std::cout << "A()" << std::endl;}
};

struct B
{
    B() {std::cout << "B()" << std::endl;}
};

struct C
{
    C() {std::cout << "C()" << std::endl;}
};

/**
 * Typelists
 */
struct NullType {};

template <typename H, typename T>
struct InheritanceList : public H, public T
{
    typedef H head_t;
    typedef T tail_t;
};

template <typename H>
struct InheritanceList<H,NullType> : public H
{
    typedef H        head_t;
    typedef NullType tail_t;
};

#define INHERITANCE_LIST_1(x)     InheritanceList<x,NullType>
#define INHERITANCE_LIST_2(x,y)   InheritanceList<x,InheritanceList<y,NullType>
#define INHERITANCE_LIST_3(x,y,z) InheritanceList<x,InheritanceList<y,InheritanceList<z,NullType> > >

/**
 * Your class
 */
struct MyClass : public INHERITANCE_LIST_3(A,B,C)
{
};

/**
 * Entry point
 */
int main( int argc, char** argv )
{
    MyClass mc;

    return EXIT_SUCCESS;
}

【讨论】:

  • Aurélien,那些宏并不是真正需要的。您也可以使用模板来做到这一点。
  • 真的!我什至没有想过使用模板,我已经习惯了这些宏,因为那是 Alexandrescu 书中的内容。感谢您的想法:)
  • 是的,我想他曾经说过他只是在使用默认模板参数之后才发现这个想法。
猜你喜欢
  • 1970-01-01
  • 2018-10-28
  • 1970-01-01
  • 1970-01-01
  • 2017-03-12
  • 2011-07-13
  • 1970-01-01
  • 2020-03-08
  • 1970-01-01
相关资源
最近更新 更多