Я пытаюсь изучить метапрограммирование шаблона C ++. Учитывая boost :: mpl :: vector классов, я хочу вычислить индекс этого класса, где статическая переменная-член имеет определенное значение.
Я нашел решение, которое, кажется, работает. Однако для правильной компиляции мне нужны странные «классы-обертки», которые кажутся ненужными. Вот мой код:
#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;
}
РЕДАКТИРОВАТЬ:
Теперь я убедился, что он на самом деле компилируется. Тем не менее, предложение Стивена также не работает. Для этого изменения я получаю эти ошибки:
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
Может ли кто-нибудь объяснить мне, что не так в моем первом решении (закомментировано) и как мне избежать необходимости использовать классы get_x и get_ind?
большое спасибо
Судя по сообщению об ошибке, похоже, вам нужно что-то вроде
mpl::int_< mpl::at<l, mpl::placeholders::_2>::type::x > >
Нам нужно передать метафункцию в if_, которая позволяет выполнять ленивую оценку после раскрытия фолда.
за
mpl::int_< mpl::at<l, mpl::placeholders::_2>::type::x >
он немедленно выполнит оценку, которая вызвала ошибку, которая не может найти ‘x’ из выражения.
Вы можете попробовать использовать костюмированную тестовую функцию вместо is_same, например,
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;
};