Reputation: 11730
I have a bimap like this:
using MyBimap = boost::bimaps::bimap<
boost::bimaps::unordered_set_of<A>,
boost::bimaps::unordered_set_of<B>>;
I want to construct it from a static initializer list, as it can be done for std::map
:
MyBimap map{{a1, b1}, {a2, b2}, {a3, b3}};
Unfortunately, it doesn't work because bimap
doesn't support initializer lists, so I tried a workaround. Boost's documentation lists the following constructors:
bimap();
template< class InputIterator >
bimap(InputIterator first,InputIterator last);
bimap(const bimap &);
So I tried the second one, like this:
std::vector<std::pair<A,B>> v{{a1, b1}, {a2, b2}, {a3, b3}};
MyBimap map(v.begin(), v.end());
It also didn't work. The documentation isn't exactly clear what kind of iterators this constructor expects, but apparently it's not simply an iterator of std::pair<A, B>
objects. Then what does this constructor expect for this kind of bimap?
Upvotes: 30
Views: 8663
Reputation: 29209
I use the following "factory function" that takes a braced initializer list and returns a boost::bimap
:
template <typename L, typename R>
boost::bimap<L, R>
make_bimap(std::initializer_list<typename boost::bimap<L, R>::value_type> list)
{
return boost::bimap<L, R>(list.begin(), list.end());
}
Usage:
auto my_bimap = make_bimap<int, int>({{1, 2}, {3, 4}, {5, 6}});
Upvotes: 31
Reputation: 2988
The iterator begin/end should be for a sequence of bimap values.
boost::bimap< A, B>::value_type
A bimap value is a lot like a std::pair and can be initialized with {a1, b1}
syntax. A vector of them seems to work too, which provides usable iterators for the constructor.
Ok, here is an example that compiles and runs for me (gcc 4.8.2 --std=c++11)
#include <vector>
#include <boost/bimap.hpp>
using namespace std;
int main() {
typedef boost::bimap< int, int > MyBimap;
std::vector<MyBimap::value_type > v{{1, 2}, {3, 4}, {5, 6}};
MyBimap M(v.begin(),v.end());
std::cout << "The size is " << M.size()
<< std::endl;
std::cout << "An entry is 1:" << M.left.at(1)
<< std::endl;
}
Upvotes: 10
Reputation: 396
C++ beginner here: You can use boost::assign to generate the initialization. I found this solution here.
Example:
#include <boost/bimap.hpp>
#include <boost/assign.hpp>
//declare the type of bimap we want
typedef boost::bimap<int, std::string> bimapType;
//init our bimap
bimapType bimap = boost::assign::list_of< bimapType::relation >
( 1, "one" )
( 2, "two" )
( 3, "three" );
//test if everything works
int main(int argc, char **argv)
{
std::cout << bimap.left.find(1)->second << std::endl;
std::cout << bimap.left.find(2)->second << std::endl;
std::cout << bimap.left.find(3)->second << std::endl;
std::cout << bimap.right.find("one")->second << std::endl;
std::cout << bimap.right.find("two")->second << std::endl;
std::cout << bimap.right.find("three")->second << std::endl;
/* Output:
* one
* two
* three
* 1
* 2
* 3
*/
}
Upvotes: 21
Reputation: 973
This leaves a vector to be cleaned up, which might in some cases be an issue. Here a short helper class that might solve your problem as well. As the class instance is a temporary, it gets cleaned up immediately wherever it is used. This is based on https://stackoverflow.com/a/1730798/3103767
// helper for bimap init (simple, lightweight version of boost::assign)
template <typename T, typename U>
class create_bimap
{
typedef boost::bimap< T, U > bimap_type;
typedef typename bimap_type::value_type value_type;
private:
boost::bimap<T, U> m_map;
public:
create_bimap(const T& left, const U& right)
{
m_map.insert( value_type(left, right) );
}
create_bimap<T, U>& operator()(const T& left, const U& right)
{
m_map.insert( value_type(left, right) );
return *this;
}
operator boost::bimap<T, U>()
{
return m_map;
}
};
Use as follows:
boost::bimap<string,int> myMap = create_bimap<string,int>
("c",1)
("b",2)
("a",3);
Upvotes: 2