简体   繁体   English

在枚举上模板化的类上的调用方法

[英]Call methods on class templatized over enum

Given the following code: 给出以下代码:

enum Fruits{ eApple, eBanana };

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

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

Is there a way to call the explicitly specialized eatIt() , for each of Fruits , without having to make each call manually? 有没有一种方法可以为每个Fruits调用显式专门化的eatIt() ,而不必手动进行每个调用?

My definition of "make each call manually" would be: 我对“手动拨打每个电话”的定义是:

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

Clearly with this method one has to extend eatAllFruits everytime Fruits is modified. 显然,使用这种方法必须在每次修改Fruits扩展eatAllFruits

My guess at this point is that you want to iterate over enum fruit automatically. 我现在的猜测是您想自动遍历枚举水果。 There is, in fact, a way to do this. 实际上,有一种方法可以做到这一点。 Have a look at this article I blogged regarding a somewhat similar problem: http://crazyeddiecpp.blogspot.com/2010/02/using-mplforeach-to-fill-tuple.html 看看我写的关于一个类似问题的这篇文章: http : //crazyeddiecpp.blogspot.com/2010/02/using-mplforeach-to-fill-tuple.html

Note the use of mpl::range and mpl::for_each. 注意mpl :: range和mpl :: for_each的使用。

Thus your eatSomeFruit() function would look something like so: 因此,您的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());
}

Firstly thanks to Noah Roberts ' answer which deserves as an upvote for being the inspiration to this answer. 首先,感谢诺亚·罗伯茨Noah Roberts)的回答,这是对这一答案的启发。

Following on from his answer I extracted and refactored boost::mpl::for_each and boost::mpl::range to obtain what I believe is the minimal complete definition which satisfies the question's criteria. 根据他的回答,我提取并重构了boost::mpl::for_eachboost::mpl::range以获得我认为是满足问题标准的最小完整定义。 It has no longer has any dependancy on Boost and is used as such: 它不再依赖Boost,因此被使用:

struct eat_fruit; // As Noah's answer

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

My EnumIteration struct is defined as below, and I welcome any comments or improvements. 我的EnumIteration结构定义如下,欢迎任何评论或改进。 The only notable difference to the Boost version is that the range excludes the final enum value (ie eTotal ), unlike boost::mpl::range which includes it. 与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 );
    }
};

The reason they're called templates is that they're not actual code - they're templates that tell the compiler what the code should look like, once you supply the missing pieces. 之所以将它们称为模板是因为它们不是实际的代码-它们是模板,一旦您提供缺少的部分,它们就会告诉编译器代码的外观。 There's no way to get the compiler to create the code without writing some other code that calls it explicitly. 没有编写其他一些明确调用它的代码,就无法让编译器创建代码。

Maybe make use of a template function? 也许利用模板功能?

template<typename F> void eatIt(F f) { /* eat it */ }

[@Dave] [@Dave]

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

somename is now a 'type' (the val# are int - they can be negative numbers) and you can use it to create variables of the type somename. somename现在是一个“类型”(val#是int-它们可以是负数),您可以使用它来创建somename类型的变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM