【问题标题】:decorator with a base that requires a constructor argument具有需要构造函数参数的基础的装饰器
【发布时间】:2009-10-21 19:18:48
【问题描述】:

我有一个类似于装饰器的模式,其基础需要构造函数参数。装饰器的构造使其可以将任意数量的附加组件作为模板参数(在本示例中最多 3 个)。

不幸的是,当指定了多个附加组件时,我无法弄清楚如何将基础的构造函数参数传递给它。在下面的示例中,CMyClass< AddOn_A > A( 100 ); 完美运行,但CMyClass< AddOn_A, AddOn_B > AB( 100 ); 在 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;
}

如果有人能指出我可能做错了什么,请告诉我。

谢谢, 保罗H

【问题讨论】:

    标签: c++ templates decorator


    【解决方案1】:

    您的错误通常源于 CMyClass 没有默认构造函数(因为您定义了 CMyClass(int) 而不是),因此有必要使用您的 CMyClass(int) 构造函数显式实例化您的父母有。因此,例如,在 CMyClass 的定义中,您需要在初始化列表中添加对 CMyClass(int) 的调用

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

    既然我们有 CMyClass 发送 x ,那么您的基本案例专业化 (CMyClass&lt;empty, empty, empty&gt;) 现在有必要拥有一个接受 x 但不执行任何操作的构造函数

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

    现在编译器可以找到正确的构造函数并按照您的期望创建类


    只是为了解释为什么像CMyClass&lt;AddOn_A&gt; A(100) 这样的行有效,这是因为A(在该示例中)只有一个父级,CMyClass&lt;empty, empty, empty&gt;,以及您的专业

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

    确实有一个默认构造函数,因为它是空的(或者更正式地说,因为它没有定义其他构造函数)。一旦你调用 CMyClass&lt;AddOn_A, AddOn_B&gt; AB(100),它就会立即崩溃,因为它有 两个 父级,CMyClass&lt;AddOn_B, empty, empty&gt;CMyClass&lt;empty, empty, empty&gt;,但是前者没有默认构造函数,所以编译器不知道如何构造它。这就是为什么我们必须将这一行添加到初始化列表中,所以我们告诉编译器使用其CMyClass(int x) 构造函数创建CMyClass&lt;AddOn_B, empty, empty&gt;(注意这意味着编译器也将尝试使用x 参数创建CMyClass&lt;empty, empty, empty&gt; ,所以我们需要向那个接受参数的特化添加一个构造函数)。

    【讨论】:

      【解决方案2】:
      • 目前尚不清楚您要达到的目标。我希望你没有混淆继承和模板。

      • emptyAddOn_AAddOn_B 是类模板。它们不是类的实例。你需要有实际的课程。

      【讨论】:

      • 我不认为我很困惑。每个附加组件都为 CBase 提供了附加功能。我正在使用递归模板模式,以使用户更容易使用而不会产生运行时损失。此外,它适用于一个插件,它只需要对多个插件进行一些调整。
      猜你喜欢
      • 2014-04-18
      • 2018-05-22
      • 2023-03-31
      • 2014-07-21
      • 2017-05-04
      • 2022-12-03
      • 2017-10-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多