2010-10-27 78 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()); 
}