2010-10-27 115 views
1

考慮下面的代碼:調用模板化方法在枚舉

enum Fruits{ eApple, eBanana }; 

template<> 
struct SomeFruit<eApple> { 
    void eatIt() { // eat an apple }; 
}; 

template<> 
struct SomeFruit<eBanana> { 
    void eatIt() { // eat a banana }; 
}; 

有沒有辦法來調用明確專門eatIt(),對於每個Fruits,而無需手動使每個電話嗎?

我的定義「使每個呼叫手動」將是:

void eatAllFruits() 
{ 
    SomeFruit<eApple> apple; 
    apple.eatIt(); 
    SomeFruit<eBanana> banana; 
    banana.eatIt(); 
} 

顯然這種方法的一個具有延伸eatAllFruitsFruits每次被修改。

+0

這並不完全清楚你想要做什麼,但它聽起來像你想要使用虛擬功能。 – 2010-10-27 15:55:13

+0

@Adam Rosenfield:我真的只是對這種模式感興趣,這個問題來自http://stackoverflow.com/questions/3997038/ – dukedave 2010-10-27 16:04:32

回答

1

首先感謝Noah Roberts的回答值得作爲給予好評的是靈感,這個答案。

從他的回答中,我提取並重構了boost::mpl::for_eachboost::mpl::range,以獲得我認爲滿足問題標準的最小完整定義。它不再對任何升壓和扶養被用作這樣的:

struct eat_fruit; // As Noah's answer 

void eatAllFruit() 
{ 
    EnumIteration< Fruits, eApple, eTotal >::for_each(eat_fruit()); 
} 

EnumIteration結構如下所定義的,我歡迎任何意見或改進。與Boost版本唯一的區別在於該範圍不包括最終的枚舉值(即eTotal),而不包括包含它的boost::mpl::range

template< typename ENUM, ENUM BEGIN, ENUM END > 
struct EnumIteration 
{ 
private: 
    template< ENUM N > 
    struct Iterator 
    { 
     static const ENUM value = N; 
     typedef Iterator< static_cast<ENUM>(N+1) > next; 
     operator ENUM() const { return static_cast<ENUM>(this->value); } 
    }; 

    template< typename T > 
    struct End 
    { enum { value = false }; }; 

    template<> 
    struct End< Iterator<END> > 
    { enum { value = true }; }; 

    template< bool done = true > 
    struct for_each_impl 
    { 
     template< typename Iterator, typename F > 
     static void execute(Iterator*, F) {} 
    }; 

    template<> 
    struct for_each_impl<false> 
    { 
     template< typename Iterator, typename F > 
     static void execute(Iterator*, F f) 
     { 
      f(typename Iterator()); 
      typedef typename Iterator::next next; 
      for_each_impl< End<next>::value >::execute(static_cast< next * >(0), f); 
     } 
    }; 

public: 
    template< typename F > 
    static void for_each(F f) 
    { 
     typedef Iterator<BEGIN> first; 
     for_each_impl< End<first>::value >::execute(static_cast< first * >(0), f); 
    } 
}; 
+0

我剛剛收到一個[C4239](http://msdn.microsoft.com/en-us/library/186yxbac),這可以通過更改'eat_fruit :: operator()(Index&)'to'eat_fruit :: operator()(Index const&)'。 – dukedave 2010-10-28 19:04:47

0

他們被稱爲模板的原因是它們不是實際的代碼 - 它們是告訴編譯器代碼應該是什麼樣子的模板,一旦你提供了缺失的部分。如果不編寫一些明確調用它的代碼,就無法讓編譯器創建代碼。

+0

是的,但是我沒有看到「缺少的部分」在這裏。我明白,在C++的限制下它可能是不可能的,但我相信編譯器在編譯時可能需要的所有信息來完成我所要求的操作。 – dukedave 2010-10-27 16:06:22

+0

@Dave,「缺失的部分」是模板參數。 – 2010-10-27 16:23:15

+0

啊是的,我明白你的意思。但在這種情況下,模板參數是枚舉值,這是在編譯時可用,請參閱我的答案:) – dukedave 2010-10-29 10:57:29

0

也許可以利用模板功能?

​​3210

[@戴夫]

enum somename 
{ 
val1 = -1, 
val2, // this will be = 0 
... 
}; 

somename現在是一個「類型」(瓦爾#是INT - 他們可以是負數),你可以用它來創建類型somename的變量。

+0

您可以擴展此?注意在我的問題中,模板參數是一個'Fruits'(所以我們可以把它看作一個'unsigned int')而不是'typename'。 – dukedave 2010-10-27 16:09:50

+0

這就是F代表的typename(int - 枚舉的是int的) – slashmais 2010-10-27 16:37:23

4

我在這一點上的猜測是,你想自動遍歷枚舉水果。事實上,有一種方法可以做到這一點。看看這篇文章,我博客有關類似的問題:http://crazyeddiecpp.blogspot.com/2010/02/using-mplforeach-to-fill-tuple.html

注意使用mpl :: range和mpl :: for_each。

因此您eatSomeFruit()函數看起來像這樣:

// modify enum... 
enum Fruits { eApple, eBananna, eFruitLast = eBananna }; 

struct eat_fruit 
{ 
    template < typename Index > 
    void operator() (Index&) 
    { 
    SomeFruit<Index::value> eater; 
    eater.eatIt(); 
    } 
}; 

void eatSomeFruit() 
{ 
    mpl::for_each< mpl::range<0, eFruitLast> >(eat_fruit()); 
}