Конвертировать boost::bimap в std::map

Очевидный способ конвертировать bimap в std::map, похоже, не работает. Ниже правильный / хороший способ конвертации? Есть ли лучший / короткий путь?

typedef boost::bimap<int, std::string> MapType;
MapType _bimap;
//Fill _bimap
MapType::left_map& lmap = _bimap.left;
//std::map<int, std::string> bmap(lmap.begin(), lmap.end()); //THIS DOESNT WORK
std::map<int, std::string> bmap;
BOOST_FOREACH(MapType::left_const_reference entry, lmap)
{
   bmap[entry.first] = entry.second;
}

1 ответ

Решение

Значения из bimap не может быть непосредственно назначен на map потому что есть проблема типа (игнорируя более очевидную проблему постоянства значения):

Когда итератор левого представления bimap разыменовывается, возвращаемый тип совместим с сигнатурой с помощью std::pair

( источник)

А также:

Тип совместим с сигнатурой с другим типом, если он имеет ту же сигнатуру для функций и метаданных. Предварительные условия, постусловия и порядок операций не обязательно должны быть одинаковыми.

Это означает, что нет никакой гарантии, что ваш bimap value_type может быть назначен или скопирован в карту value_type. На самом деле это не так:

typedef boost::bimap<int, std::string> BiMapType;
typedef std::map<int, std::string> MapType;

BiMapType bimap;
BiMapType::left_value_type t1 = *(bimap.left.begin()); // Mandatory for compilation on my version at least
MapType::value_type t2(t1);

Это ужасно потерпит неудачу (то же самое, если вы попытаетесь t2 = t1;)

Так что либо вы найдете способ конвертировать значения-значения, либо сохраните их в for_each/transform/copy ... идиоме.

В комментарии @CharlesPehlivanian (который он, возможно, также предоставит в качестве ответа) здесь есть замечательное решение, которое должно использоваться boost::trasnform_iterator,

Для этого вы должны предоставить transformer функтор (он не работает с необработанной лямбда, вы должны использовать структуру с operator() а также result_type или std::function), который преобразует входное значение итератора в выходное значение:

    typedef std::function<MapType::value_type (const BiMapType::left_value_type&)>
        Transformer;
    Transformer transformer_func = [](const BiMapType::left_value_type& elem)
        {
            return std::make_pair(elem.first, elem.second);
        };

Тогда вам просто нужно обернуть начало и конец итератора boost::make_transform_iterator:

    auto begin = boost::make_transform_iterator(bimap.left.begin(), transformer_func);
    auto end = boost::make_transform_iterator(bimap.left.end(), transformer_func);

Вот весь код:

#include <boost/bimap.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <map>

int main(int argc, char const *argv[])
{
    typedef boost::bimap<int, std::string> BiMapType;
    typedef std::map<int, std::string> MapType;
    typedef std::function<MapType::value_type (const BiMapType::left_value_type&)>
        Transformer;

    BiMapType bimap;


    Transformer transformer_func = [](const BiMapType::left_value_type& elem)
        {
            return std::make_pair(elem.first, elem.second);
        };

    auto begin = boost::make_transform_iterator(bimap.left.begin(), transformer_func);
    auto end = boost::make_transform_iterator(bimap.left.end(), transformer_func);

    MapType map(begin, end);

    return 0;
}

http://coliru.stacked-crooked.com/a/8fae0d47ca4b72a1

Другие вопросы по тегам