0

I am trying to learn C++ template metaprogramming. Given a boost::mpl::vector of classes I want to compute the index of that class where a static member variable has a certain value.

I found a solution which seems to work. However, in order to compile correctly I need some strange 'wrapper-classes' which seem unecessary. Here is my code:

#include <iostream>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/range_c.hpp>

using namespace boost;

template<typename T>
struct get_ind {
    typedef mpl::int_<T::type::value> type;
};

template <typename T>
struct get_x {
typedef mpl::int_<T::x> type;
};

template<typename l>
struct clist {
typedef mpl::range_c<int, 0, mpl::size<l>::type::value > indices;
typedef mpl::fold<
    indices, mpl::size<l>,
    mpl::if_<
        is_same<

// HERE:
    get_x<mpl::at<l, get_ind<mpl::placeholders::_2> > >
// 
//  mpl::int_< mpl::at<l, mpl::placeholders::_2>::type::x > 
//  mpl::int_<mpl::at<l, mpl::placeholders::_2> >::x >  
        , mpl::int_<1>   >  
                     ,
    mpl::placeholders::_2, mpl::placeholders::_1 >
> index;
};


struct A {
static const int x = 1;
};

struct B {
static const int x = 0;
};


int main(int argc, char*argv[]) {

typedef boost::mpl::vector<A, B> classes;
typedef clist<classes> classlist;

std::cout << "result " << classlist::index::type::value<<std::endl;
return 0;
}

EDIT:

I have now made shure that it actually compiles. However, Steven's suggestion also doesn't work. For that change I get these errors:

test.cpp: In instantiation of ‘clist<boost::mpl::vector<A, B, mpl_::na, mpl_::na,     
mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_    
::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na> >’:
test.cpp:56:   instantiated from here
test.cpp:38: error: ‘x’ is not a member of ‘mpl_::void_’
test.cpp: In function ‘int main(int, char**)’:
test.cpp:56: error: ‘classlist::index’ is not a class or namespace

Could anyone please explain to me what is wrong in my first solution (commented out) and how I can avoid the need for classes get_x and get_ind?

many thanks

jomulu
  • 1
  • 1
  • In my environment it doesn't compile. Please add `#include ` and `using namespace boost;` after the other includes. After adding this and trying your other variant the result was, beside a lot of other errors, a syntax error. In the working solution are 3 `<` and 3 `>` and in the not working soultion are 2 `<` and 3 `>`. You have to fix this and I think you should take more work into formating and documenting. – Jan Herrmann Jun 05 '13 at 13:17

2 Answers2

1

Based on the error message, it looks like you'll need something like

mpl::int_< mpl::at<l, mpl::placeholders::_2>::type::x > > 
Steven Maitlall
  • 777
  • 3
  • 5
1

We need to pass a metafunction to if_ which is possible to do lazy evaluation after fold expanded.

for

mpl::int_< mpl::at<l, mpl::placeholders::_2>::type::x >

it will do evaluation immediately, which generated the error that can't find 'x' from the expression.

You can try to use a costumed test function instead of is_same, e.g.

template <typename T, typename V>
struct has_value
    : mpl::bool_<T::x == V::value>
{};

template<typename l>
struct clist {
  typedef mpl::range_c<int, 0, mpl::size<l>::type::value > indices;
  typedef mpl::fold<
    indices, mpl::size<l>,
    mpl::if_<
      has_value<
        mpl::at<l, mpl::placeholders::_2>
        , mpl::int_<1>   >  
      ,
      mpl::placeholders::_2, mpl::placeholders::_1 >
    > index;
};
qduyang
  • 353
  • 1
  • 8