Метавычисление типов в Boost MPL

322
17 октября 2017, 03:28

У меня есть задача:

Дана последовательность типов. Проверить, что все они являются классами и упорядочить их так, чтобы производные классы находились раньше их базовых. Для полученной последовательности проверить, что все классы являются производными от последнего.

Реализовать решение необходимо с помощью boost::mpl. В данный момент у меня есть Swap, которая меняет местами 2 элемента в последовательности, например в mpl::vector:

template< typename Seq, typename First, typename Second >
struct swap {
private:
    typedef typename begin<Seq>::type begin;
    typedef typename end<Seq>::type   end;
    typedef typename clear<Seq>::type empty_container;
// Insert values from begin to first
typedef typename
    copy<
    iterator_range< begin, First >,
    back_inserter< empty_container >
    >::type prefix;
// Insert second value 
typedef typename
    push_back<
    prefix, typename
    deref< Second >::type
    >::type prefixSecond;
// Insert values from first+1 to second
typedef typename
    copy<
    iterator_range< typename next< First >::type, Second >,
    back_inserter< prefixSecond >
    >::type prefixSecondMiddle;
// Insert first value
typedef typename
    push_back<
    prefixSecondMiddle, typename
    deref< First >::type
    >::type prefixSecondMiddleFirst;
// Insert values from second+1 to end
typedef typename
    copy<
    iterator_range< typename next< Second >::type, end >,
    back_inserter< prefixSecondMiddleFirst >
    >::type prefixSecondMiddleFirstSuffix;
public:
     typedef prefixSecondMiddleFirstSuffix type;
};

Вот пример использования:

typedef typename boost::mpl::next<myvector::begin>::type first;
typedef typename boost::mpl::next<first>::type second;
typedef swap<myvector, first, second>::type res;

И предикат, который проверяет, что первый элемент является родителем второго:

template< typename T1, typename T2 >
struct compare_two{
    static const bool value = is_base_of<T1, T2>::value;
};

Теперь, допустим, у нас дан список типов:

class base1 {};
class child1 : base1 {};
class child2 : child1 {};
class child3 : child2 {};
typedef vector<child2, child1, base1, child3> vec;

Надо, чтобы после применения метафункции получилось: child3, child2, child1, base1

Как я понимаю, надо просто отсортировать вектор, меняя соответствующие типы местами, если первый - предок второго. Подскажите, как реализовать это средствами Boost MPL?

Answer 1

Как-то так:

#include <boost/mpl/sort.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/count_if.hpp>
#include <boost/mpl/equal.hpp>
#include <boost/type_traits.hpp>
namespace mpl = boost::mpl;
struct A {};
struct B: A {};
struct C: B {};
struct D: A {};
struct E: C, D {};
// Функция сревнения - базовый класс меньше наседника
struct is_base_of_fn{
    template <class Base, class Derived> struct apply{
        using type = boost::is_base_of<Base, Derived>;
    };
};
struct is_class_fn{
    template <class T> struct apply{
        using type = boost::is_class<T>;
    };
};
template <class Seq>
using is_seq_of_class = mpl::bool_<mpl::count_if<Seq, is_class_fn>::type::value == mpl::size<Seq>::value>;
using input_type_set = mpl::vector<E,B,D,C,A>;
static_assert(is_seq_of_class<input_type_set>::value, "");
using outpur_type_set = typename mpl::sort<input_type_set, is_base_of_fn>::type;
static_assert(mpl::equal<outpur_type_set, mpl::vector<A,B,D,C,E>>::value, "");

P.S. Рекомендую к прочтению эту статью (про метопрограммирование, не про mpl)

READ ALSO
C++ компилятор не читает дробные числа [дубликат]

C++ компилятор не читает дробные числа [дубликат]

На данный вопрос уже ответили:

348
Стоит ли заменить подход std:thread на std::async?

Стоит ли заменить подход std:thread на std::async?

В проекте (многоагентная система для работы с потоком разнотиповых данных в реальном времени) используется многопоточность из стандартной...

252
Как считать массив из файла?

Как считать массив из файла?

Программа должна считывать массив из файла и искать в нём минимальный элемент, но что-то не получается нормально считать сам массивВ чем...

547
Пароль через CreateFile для PhysicalDrive1

Пароль через CreateFile для PhysicalDrive1

Возможно ли через функцию CreateFile установить пароль на PhysicalDrive1, те

231