2009-10-22 80 views
1

我有一個類可以用一組附加模板來裝飾以提供附加功能。每個插件都有一個基類需要知道的標識addon_value。模板元編程OR操作

下面的代碼是我想要做的一個例子。顯然,main()函數無法編譯。目標是讓CBase :: GetValueOfAddOns()知道每個附加組件的addon_value的OR值。該計算實際上並不需要在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 " ([email protected]@@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; 
} 

感謝您的幫助, PaulH

+3

您不能從構造函數或析構函數調用虛擬方法。這是未定義的行爲。 – 2009-10-22 15:41:12

+0

@Martin York - 那麼,有沒有辦法在CBase ctor()中獲得addon_value還是不合理? – PaulH 2009-10-22 15:49:11

+1

Martin York:調用虛函數很好,除非它們是純粹的。混淆人的唯一原因是他們只會指向已構建的最衍生對象 - 這幾乎總是意味着調用實際上不是虛擬的。同樣對於析構函數 - 調用未完成其析構函數的大多數派生對象。 – coppro 2009-10-22 16:16:06

回答

2

不知道這是最優雅的方式,但以下是相當簡單:

一下添加到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<empty, empty, empty>

enum {AddonsValues = 0}; 
+0

我不知道。至少它至少比其他代碼還要優雅。我喜歡。 :) – PaulH 2009-10-22 15:25:24

1

如果你作出這樣的功能純virtual,您可以在CMyClass,在那裏你必須提供的所有信息,實現它。只需更改您的empty類以定義enum { addon_value = 0x00000000 };,這將使這更容易。

+0

That + Eric的評論上面的工作很好,除了CBase()還不能「知道」這個價值。我修改了原始文章中的代碼以顯示鏈接器錯誤。當我嘗試從CBase :: ctor訪問GetValueOfAddons()時,我會得到它。有什麼建議麼? 謝謝 – PaulH 2009-10-22 15:24:29

+0

爲什麼要從'CBase'的ctor調用該函數?虛擬功能不能像大多數人所期望的那樣工作。如果它只是ctor,那麼可以將該值作爲參數傳遞給它。否則,虛擬功能將起作用。 – sbi 2009-10-22 17:31:45

0

讓我們做得更好:

看到你的新問題a回合the problem with hierarchy here我已經解決了AddOnValues問題,並且不需要模板元編程。