Question

The obvious way to convert a bimap to std::map, doesnt seem to work. Is below the correct/good way to convert? Is there a better/shorter way?

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;
}
Was it helpful?

Solution

The values from a bimap cannot be directly assigned to thos of a map because there is a problem of type (ignoring the more obvious problem of const-ness of the value):

When a bimap left view iterator is dereferenced the return type is signature-compatible with a std::pair< const A, const B >

(source)

And :

A type is signature-compatible with other type if it has the same signature for functions and metadata. Preconditions, postconditions and the order of operations need not be the same.

That means that there is no guarantee that your bimap value_type is assignable or copyable to a map value_type. In fact it is not:

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);

That will fail horribly (same kind of thing if you try t2 = t1;)

So either you find a way to convert your value_types either you keep with a for_each/transform/copy ... idiom.

There is a neat solution signaled here in comment by @CharlesPehlivanian (that he will maybe provide as an answer also), that is to use boost::trasnform_iterator.

For that you have to provide a transformer functor (it does not work with a raw lambda, you have to use a struct with operator() and result_type or a std::function) that will convert the input iterator value to the output one:

    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);
        };

Then you just have to wrap begin and end iterator with 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);

Here is the whole code:

#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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top