问题
The following example demonstrates what I mean:
#include <boost/mpl/map.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/insert.hpp>
#include <iostream>
using namespace boost::mpl;
template <int n1, int n2>
struct entry
{
typedef pair<int_<n1>, int_<n2> > type;
};
typedef map<entry<1,1>::type> entries;
typedef insert<
entries, entry<4,4>::type>::type update;
typedef insert<
update,
entry<5,5>::type>::type update2;
struct print_values
{
template <class I>
void operator()(I)
{
std::cout << first<I>::type::value << ", "
<< second<I>::type::value << std::endl;
}
};
int main()
{
for_each<update2>(print_values());
std::cout << "Next:" << std::endl;
for_each<update2::type>(print_values());
}
outputs:
1, 1
4, 4
5, 5
Next:
1, 1
When I evaluate update2
by accessing update2::type
the items I inserted disappear.
Why does this happen and what can I do to to make sure the evaluating update2
doesn't remove the inserted elements?
回答1:
I'm convinced this is a bug in boost::mpl
.
The result of inserting an element into an mpl::map
is not an item of type mpl::map
but of mpl::m_item
. This m_item
holds the newly inserted key and value as well as the map they were inserted into.
Now every class in boost::mpl
is a metafunction, containers are a metafunction that return themselves. This is useful for situations like this
typedef map<pair<int,int> > i_map;
eval_if<true_,
i_map,
at<i_map, float> >::type type;
So mpl::map
has a typedef inside it that is simply typedef map type;
, m_item
, however, lacks this typedef
and so since it derives from the map
it's inserted into m_item::type
is actually map::type
.
This means my example after insertion (dropping the int_<>
for brevity) looks like:
m_item<5, 5, m_item<4, 4, map1<pair<1, 1> > > >
and accessing its type reaches all the way back up to map1<pair<1, 1> >::type
which returns map<pair<1, 1> >
which is why all the inserted items are disappearing.
I logged a bug and was originally waiting for a response before posting this answer but after 4 weeks I decided to post this without any answer from them.
The solution is to simply add typedef m_item type;
to boost::mpl::m_item
in boost/mpl/map/aux_/item.hpp
. This will make m_item
a metafunction that correctly returns itself and not return the original map.
来源:https://stackoverflow.com/questions/17393496/inserted-items-disappear-from-boostmplmap