Можно ли использовать карту boost fusion в обратном порядке, она же ключ 567, значение type ?

Я хотел бы иметь значение для типа карты, и из того, что я вижу, boost fusion использует карту, которая использует пару, где тип всегда является первым членом (так что это ключ на карте)?

map_type m(
    fusion::make_pair<int>('X')
  , fusion::make_pair<double>("Men"));

Можно ли сделать значение (например, «X» в приведенном выше примере) ключом и значением типа? Если нет, могу ли я, по крайней мере, сделать фильтр на основе значения (это медленно, поэтому было бы неплохо узнать, могу ли я отсортировать вектор слияния на основе второго параметра и использовать для него бинарный_поиск (опять же с пользовательским компаратором, который смотрит на значение, а не на ключ) .


person NoSenseEtAl    schedule 30.06.2013    source источник


Ответы (2)


Может быть, не в boost::fusion, но в трюке, когда вы берете список значений времени выполнения и вызываете функтор с типом, зависящим от того, какие совпадения существуют. Я называю это волшебным переключателем.

Вам нужно перечислить типы во время компиляции, а затем связать тип времени выполнения со смещением в указанном списке. tuple уже сопоставляет индексы с типами для вас.

Вы не можете вернуть тип, но вместо этого вы можете вызвать переданную в шаблоне функцию с типом.

Однако, прежде чем идти по этому пути, вы должны иметь в виду конкретную цель и посмотреть, есть ли; есть менее запутанные способы ее решения.

person Yakk - Adam Nevraumont    schedule 30.06.2013
comment
на самом деле мотивацией был волшебный переключатель... stackoverflow.com/questions/16691214/ недавно я наткнулся на слияние, и мне стало интересно, может быть, слияние - это магия, которую я искал :) - person NoSenseEtAl; 30.06.2013

Интересный вопрос. Обычно это не будет работать, потому что на самом деле нет способа представить тип во время выполнения с той же семантикой, которая известна во время компиляции, например, нет виртуальных конструкторов (см. страницу 200 «Moder C++ Design», параграф 8.2). Но fusion поддерживает for_each, который перебирает во время компиляции последовательность и вызывает объект функции времени выполнения. Теперь этот функциональный объект может быть универсальным фильтром, перенаправляющим вызов другому универсальному функциональному объекту, если его универсальный предикат возвращает значение true.

Теперь ее код:

#include <boost/fusion/container/map.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>

#include <string>
#include <iostream>
#include <typeinfo>

using namespace boost::fusion;


template<class Pred,class Fun>
 struct filter {
    Pred pred_;
    Fun& fun_;

    filter(Pred p, Fun& f)
        : pred_(p)
        , fun_(f)
    {}

    template<class Pair>
    void operator()(Pair& pair) const {
        if (pred_(pair.second))
            fun_(pair);
    }
 };

 template<class Pred,class Fun>
 filter<Pred,Fun> make_filter(Pred p, Fun& f) {
    return filter<Pred,Fun>(p, f);
 }

 typedef map 
    < pair<int, char>
    , pair<double, std::string>
 > map_type;

 struct fun {
    template<class First,class Second>
    void operator()(pair<First,Second>& t) const {
        std::cout 
            << typeid(First).name() << std::endl
            << typeid(Second).name() << ":" << t.second << std::endl;
    }
 };

 struct mypred {
    template<class T>
    bool operator()(T const&) const {
        return false;
    }

    bool operator()(char c) const {
        return c=='X';
    }
};

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

    map_type m(
        make_pair<int>('X'), 
        make_pair<double>("Men")
    );

    for_each(m, make_filter(mypred(),fun()));

    return 0;
}

Класс фильтра хранит предикат и функциональный объект. Если предикат возвращает true на pair.second, в вашем случае 'X' он вызывает объект функции. make_filter — небольшой помощник для создания фильтра. Теперь осталось два фрагмента кода: мой особый предикат mypred, который принимает только char (вам придется иметь дело с перегрузкой для более общих реализаций) и мой функциональный объект fun, который выводит информацию о типе и значение. В основном for_each вызывается с filter. Обратите внимание: фильтр предназначен для получения объекта функции по ссылке, чтобы он мог передавать аргументы и результат. В конце концов, это вариант специального посещения. Если вас беспокоит скорость, вы должны знать, что практически все можно встроить. В этом конкретном примере сравниваются только символы, для всех остальных типов результат равен false, и функция не вызывается. Конечно, есть много возможностей для улучшения, но у меня сейчас нет времени этим заниматься. Возможно, есть лучшие способы реализовать это, но это была моя первая программа с boost.fusion :-).

person Jan Herrmann    schedule 12.07.2013