views:

36

answers:

1

I have a list of types defined as:

typedef boost::mpl::list<Apple, Pear, Brick> OriginalList;

I would like to create a second list that does not contain any fruit, i.e. the resultant list formed from the first list would contain a single type Brick. Fruit is identified through a static const variable defined within the types, e.g.:

struct Apple
{
    static const bool IsFruit = true;
};

I currently have a solution that involves creating a meta-function class, and using boost::mpl::remove_if. I believe I should be able to make this more elegant by using boost::mpl::lambda to remove the need for the separate RemoveFruit struct. Any suggestions on how to do this?

Full code as it currently stands:

include <boost/static_assert.hpp>
#include <boost/mpl/list.hpp>
#include <boost/mpl/remove_if.hpp>
#include <boost/mpl/size.hpp>

#include <iostream>

struct Apple
{
  static const bool IsFruit = true;
};

struct Pear
{
  static const bool IsFruit = true;
};

struct Brick
{
  static const bool IsFruit = false;
};

typedef boost::mpl::list<Apple, Pear, Brick> OriginalList;
BOOST_STATIC_ASSERT(boost::mpl::size<OriginalList>::type::value == 3);

// This is what I would like to get rid of:
struct RemoveFruit
{
  template <typename T>
  struct apply
  {
    typedef boost::mpl::bool_<T::IsFruit> type;
  };
};

// Assuming I can embed some predicate directly in here?
typedef boost::mpl::remove_if<
  OriginalList,
  RemoveFruit
  >::type NoFruitList;

BOOST_STATIC_ASSERT(boost::mpl::size<NoFruitList>::type::value == 1);

int main()
{
  std::cout << "There are " << boost::mpl::size<OriginalList>::type::value << " items in the original list\n";
  std::cout << "There are " << boost::mpl::size<NoFruitList>::type::value << " items in the no fruit list\n";


  return 0;
}
+2  A: 

I think the best you can do is to define an IsFruit struct like

template  <typename T> struct isFruit : boost::mpl::bool_<T::IsFruit> {};

And then you can define your no-fruit list as

typedef boost::mpl::remove_if<
  OriginalList,
  boost::mpl::lambda< isFruit< boost::mpl::_1 > >::type
  >::type NoFruitList;

The additional struct is needed to get access to the IsFruit field in your classes.

Note that if you want to get rid of the additional struct entirely, you'll have to rename the boolean members of your other classes. If you follow the boost::mpl convention and call them value instead of IsFruit, you can define NoFruitList as

typedef boost::mpl::remove_if<
      OriginalList,
      boost::mpl::lambda<boost::mpl::_1>::type
      >::type NoFruitList;
JRM
That's perfect. Thanks. Just a quick follow up question. I can't rename IsFruit to value, but would it be possible to change the type from a `static const bool` to a `boost::mpl::bool_<>` and access the value that way?
Shane
Unfortunately, I don't know of any way to make that work. Essentially, the name 'value' is used internally by mpl algorithms to get at any value field (just like 'type' is used to get at type fields). In this case, lambda will use the value field to generate a metafunction class that has the same effect as your RemoveFruit metafunction. If you can't rename, you need some other mechanism to tell mpl what field you want to use. In my example, that would be the isFruit struct which essentially maps the IsFruit field of your classes to bool_'s value field.
JRM
Fair enough. Thanks.
Shane