Сочетание типов с использованием boost :: mpl - PullRequest
4 голосов
/ 24 июля 2010

У меня есть список типов, из которого я хочу построить список всех комбинаций с двумя элементами.Например:

namespace mpl = boost::mpl;
typedef mpl::vector<int, long> typelist;
// mpl magic...
// the wanted list is equivalent to:
typedef mpl::vector<pair<int, int>, pair<int, long>,
                    pair<long, int>, pair<long, long> > combinations;

Здесь pair<T1,T2> может быть std::pair<T1,T2> или mpl::vector<T1,T2>.Как это сделать?Мне также было бы интересно удалить дубликаты, если учесть, что pair<T1, T2> == pair<T2, T1>.
Спасибо.

Ответы [ 3 ]

6 голосов
/ 24 июля 2010

Список комбинаций одного типа int со списком типов mpl::vector<int, long> можно вычислить, вызвав mpl::fold:

typedef fold<
    mpl::vector<int, long>, vector<>, 
    push_back<mpl::_1, std::pair<int, mpl::_2> > 
>::type list_of_pairs;

Теперь, если мы обернем это в отдельный мета-функция и вызовите его для всех типов исходного списка типов, которые мы получаем:

typedef mpl::vector<int, long> typelist;

template <typename T, typename Result>
struct list_of_pairs
  : mpl::fold<typelist, Result, 
        mpl::push_back<mpl::_1, std::pair<T, mpl::_2> > > 
{};

typedef mpl::fold<
    typelist, mpl::vector<>, mpl::lambda<list_of_pairs<mpl::_2, mpl::_1> >
>::type result_type;

BOOST_MPL_ASSERT(
    mpl::equal<result_type, 
        mpl::vector4<
            std::pair<int, int>, std::pair<int,long>,
            std::pair<long,int>, std::pair<long,long> 
        > >::value);

РЕДАКТИРОВАТЬ: ответ на второй вопрос:

Создание результата, содержащего только уникальные элементы (в смыслеВы упомянули) немного более сложным.Сначала вам нужно определить мета-функцию, сравнивающую два элемента и возвращающую mpl :: true_ / mpl :: false _:

template <typename P1, typename P2>
struct pairs_are_equal
  : mpl::or_<
        mpl::and_<
            is_same<typename P1::first_type, typename P2::first_type>,
            is_same<typename P1::second_type, typename P2::second_type> >,
        mpl::and_<
            is_same<typename P1::first_type, typename P2::second_type>, 
            is_same<typename P1::second_type, typename P2::first_type> > >
{};

Затем нам нужно определить мета-функцию, которая пытается найти данный элемент взаданный список:

template <typename List, typename T>
struct list_doesnt_have_element
  : is_same<
        typename mpl::find_if<List, pairs_are_equal<mpl::_1, T> >::type, 
        typename mpl::end<List>::type>
{};

Теперь это можно использовать для создания нового списка, убедившись, что дубликаты не вставлены:

typedef mpl::fold<
    result_type, mpl::vector<>,
    mpl::if_<
        mpl::lambda<list_doesnt_have_element<mpl::_1, mpl::_2> >, 
        mpl::push_back<mpl::_1, mpl::_2>, mpl::_1>

>::type unique_result_type;

Все это из головы,так что может понадобиться немного подправить здесь или там.Но идея должна быть правильной.


РЕДАКТИРОВАТЬ: незначительные исправления, как указано в @ rafak

2 голосов
/ 24 июля 2010

Отличный вопрос.Есть много интересных способов решить эту проблему.Вот один.

Все неквалифицированные имена находятся в пространстве имен mpl, за исключением _1 и _2, которые находятся в mpl::placeholders и boost::is_same, которые находятся в библиотеке type_traits.Первый шаблон является вспомогательным классом для генерации списка всех пар, состоящих из одного элемента и каждого элемента данной последовательности.Второй шаблон объединяет все результаты вместе, чтобы сформировать окончательную последовательность.Обратите внимание, что результаты не в векторе.Это легко сделать с помощью mpl :: copy.

template <class Elem, class Seq>
struct single_combo {
    typedef typename transform<Seq
            ,lambda< std::pair<Elem, _1> >
        >::type type;
};

template <class Seq>
struct combo {
    typedef typename unique<Seq, is_same<_1,_2> >::type U;
    typedef typename fold<
        typename transform<U
            ,lambda< single_combo<_1, U> >
            >::type
        ,empty_sequence
        ,lambda< joint_view<_1,_2> >
    >::type type;
};

typedef typename combo<typelist>::type combinations;

Примечание: если вы читаете это письмо и хотите получить вызов, попробуйте ответить на этот вопрос самостоятельно.Это отличное погружение в MPL.

0 голосов
/ 24 июля 2010

В последнее время я сам занимался метапрограммированием. Вы смотрели на boost :: mpl :: set?Это устранит дубликаты.Что касается комбинаций, это звучит для меня как отображение, как насчет boost :: mpl :: map?Помните, что существуют ограничения библиотеки, которые накладываются на ограничения типов, которые могут принимать последовательности, хотя это можно отрегулировать с помощью макроса, вы все еще зависите от верхнего предела вашего компилятора, в зависимости от количества типов, которое вам нужноручка.

...