【问题标题】:template meta-programming OR operation模板元编程或操作
【发布时间】:2009-10-22 14:43:38
【问题描述】:

我有一个可以用一组附加模板装饰的类,以提供额外的功能。每个附加组件都有一个基类需要知道的标识 addon_value。

下面的代码是我想做的一个例子。显然,main() 函数无法编译。目标是让 CBase::GetValueOfAddOns() 知道每个附加组件对 addon_value 进行 OR-ing 的值。计算实际上不必在 GetValueOfAddOns() 中执行,它只需要能够得到结果即可。

template< class T >
class AddOn_A : public T
{
public: 
    AddOn_A( int x ) : T( x ) 
    {};

    enum { addon_value = 0x00000001 };
};

template< class T >
class AddOn_B : public T
{
public: 
    AddOn_B( int x ) : T( x ) 
    {};

    enum { addon_value = 0x00000010 };
};

class CBase
{
public:
    explicit CBase( int x ) : x_( x ) 
    {
        // error LNK2001: unresolved external symbol "public: virtual int __thiscall CBase::GetValueOfAddOns(void)const " (?GetValueOfAddOns@CBase@@UBEHXZ)
        int z = GetValueOfAddOns();
    };

    virtual int GetValueOfAddOns() const = 0;

private:
    int x_;
};

// define an empty AddOn
template< class > class empty 
{
public:
    enum { addon_value = 0x00000000 };
};

// 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 > : public CBase
{
public:
    CMyClass( int x ) : CBase( x ) 
    {};

    enum { addon_value = 0x00000000 };
};

// 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:
    CMyClass( int x ) : AddOn1< CBase >( x ),
                        CMyClass< AddOn2, AddOn3 >( x )
    {};

    enum { addon_value = AddOn1< CBase >::addon_value | CMyClass< AddOn2, AddOn3 >::addon_value };

    int GetValueOfAddOns() const
    {
        return addon_value;
    }
};

int _tmain( int argc, _TCHAR* argv[] )
{
    CMyClass< AddOn_A > A( 0 );
    _ASSERT( A.GetValueOfAddOns() == AddOn_A< CBase >::addon_value );

    CMyClass< AddOn_A, AddOn_B > AB( 0 );
    _ASSERT( AB.GetValueOfAddOns() == ( AddOn_A< CBase >::addon_value | AddOn_B< CBase >::addon_value ) );

    return 0;
}

感谢您的帮助, 保罗H

【问题讨论】:

  • 你不能从构造函数或析构函数调用虚方法。这是未定义的行为。
  • @Martin York - 那么,有没有办法在 CBase ctor() 中获取 addon_value 或者这不合理?
  • Martin York:调用虚函数很好,除非它们是纯函数。唯一让人们感到困惑的是,他们只会指向已构造的最派生对象——这几乎总是意味着调用实际上不是虚拟的。对于析构函数也是如此——调用尚未完成析构函数的最派生对象。
  • @martin:您的评论让我们希望我们可以否决 cmets。这当然不是未定义的行为——除非函数是纯虚拟的。
  • @coppro 和@sbi:虽然我同意这不是未定义的行为......事实上它只调用了当前的虚拟覆盖(可能是未定义的......)使得很难使用...,我肯定会给任何初学者提供与 Martin 相同的建议!

标签: c++ templates decorator


【解决方案1】:

不确定这是最优雅的方式,但以下方法相当简单:

将此添加到 CMyClass:

enum {AddonsValues = AddOn1<CBase>::addon_value | CMyClass<AddOn2, AddOn3>::AddonsValues};

int GetValueOfAddOns()
{
    // return the result of OR-ing the addon_value of each add-on.
    return AddonsValues;
};

这个给专门的CMyClass&lt;empty, empty, empty&gt;

enum {AddonsValues = 0};

【讨论】:

  • 我不知道。至少它的优雅程度不亚于其他代码。我喜欢。 :)
【解决方案2】:

如果您将该函数设为纯virtual,您可以在CMyClass 中实现它,您可以在其中获得所有可用信息。只需将您的empty 类更改为定义enum { addon_value = 0x00000000 };,这将使这更容易。

【讨论】:

  • 上面那个 + Eric 的评论效果很好,除了 CBase() 仍然不能“知道”这个值。我已经修改了原始帖子中的代码以显示链接器错误。当我尝试从 CBase::ctor 访问 GetValueOfAddons() 时,我得到了。有什么建议么?谢谢
  • 为什么要从CBase 的ctor 调用该函数?虚函数并不像大多数人期望的那样从 ctors 和 dtors 工作。如果它只是 ctor,您可以将值作为参数传递给它。否则,虚函数将起作用。
【解决方案3】:

让我们变得更好:

看看你关于the problem with hierarchy here的新问题我也解决了那里的AddOnValues问题,真的不需要模板元编程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-16
    • 2012-01-25
    • 1970-01-01
    • 2012-11-21
    • 1970-01-01
    • 2013-05-06
    • 2018-11-11
    相关资源
    最近更新 更多