我有一个类似装饰器的模式,其基础需要构造函数参数。装饰器的构造使其可以采用任意数量的附加组件作为模板参数(在本示例中最多为 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;
}

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

谢谢,保罗

有帮助吗?

解决方案

您的错误通常源于以下事实: CMyClass 没有默认构造函数(因为您定义了一个 CMyClass(int) 相反),因此有必要使用显式实例化你的父母 CMyClass(int) 你拥有的构造函数。因此,例如,在您的定义中 CMyClass 您需要将调用添加到 CMyClass(int) 在初始化列表中

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

现在我们有了 CMyClass 发送 x 总而言之,您的基本案例专业化是必要的(CMyClass<empty, empty, empty>)现在有一个接受的构造函数 x 但没有做任何事

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

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


只是为了解释为什么像这样的行 CMyClass<AddOn_A> A(100) 工作,这是因为 A (在那个例子中)只有一个父母, CMyClass<empty, empty, empty>, ,以及你的专业

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

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

其他提示

  • 目前尚不清楚您想要实现什么目标。我希望您没有混淆继承和模板。

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top