开发者

Call methods on class templatized over enum

开发者 https://www.devze.com 2023-01-22 01:31 出处:网络
Given the following code: enum Fruits{ eApple, eBanana }; template<> struct SomeFruit< eApple > {

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?

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.


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

Note the use of mpl::range and mpl::for_each.

Thus your eatSomeFruit() function would look something like so:

// 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.

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. It has no longer has any dependancy on Boost and is used as such:

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. The only notable difference to the Boost version is that the range excludes the final enum value (i.e. eTotal), unlike boost::mpl::range which includes it.

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]

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消