views:

80

answers:

4

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.

A: 

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.

Mark Ransom
Yes, however I don't see what the "missing pieces" are here. I understand that it may not be possible within the constraints of C++, but I believe all the information the compiler could need to do what I have asked is available at compile time.
Dave Tapley
@Dave, the "missing pieces" are the template parameters.
Mark Ransom
@Mark, ah yes I see what you mean. But in this case the template parameters are the enum values, which are available at compile time, see my answer :)
Dave Tapley
A: 

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.

slashmais
Could you expand upon this? Notice that in my question the template parameter is a `Fruits` (so we can think of it as an `unsigned int`) and not a `typename`.
Dave Tapley
That is what typename F represent (int - enum's are int's)
slashmais
+4  A: 

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());
}
Noah Roberts
+1  A: 

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 );
    }
};
Dave Tapley
Dave Tapley