我使用multi_index_container来跟踪插入顺序并进行映射工作(如LinkedMap of Java)。
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include "CppUnitTest.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
template<typename KeyType, typename MappedType>
struct LinkedMap {
typedef std::pair<KeyType, MappedType> value_type;
typedef boost::multi_index_container<
value_type,
boost::multi_index::indexed_by<
boost::multi_index::random_access<>,
boost::multi_index::ordered_unique<
boost::multi_index::member<value_type, KeyType, &value_type::first>
>
>
> type;
};
TEST_CLASS(LinkedMapTest) {
public:
TEST_METHOD(ShouldUpdateEntry) {
LinkedMap<int, std::wstring>::type userMap;
userMap.push_back(std::make_pair(1, L"John"));
userMap.push_back(std::make_pair(1, L"Tom")); // 2nd push_back
auto& idToNameMap = userMap.get<1>();
auto& iter = idToNameMap.find(1);
Assert::AreEqual(std::wstring(L"Tom"), iter->second);
}
};
测试用例失败。
结果消息:断言失败。预期:其中汤姆&GT;实际:其中约翰&GT;
这意味着第二个push_back不会更新该值。
我的代码出了什么问题?我怎么能实现LinkedMap?
答案 0 :(得分:1)
您指定的有序索引是唯一:
boost::multi_index::ordered_unique<
boost::multi_index::member<value_type, KeyType, &value_type::first>
>
使其不唯一以允许重复键:
boost::multi_index::ordered_non_unique<
boost::multi_index::member<value_type, KeyType, &value_type::first>
>
或者,如果您的密钥需要是唯一的,并且您想要更新现有条目,您可以执行类似(未经测试)的操作:
auto& idToNameMap = userMap.get<1>();
auto& iter = idToNameMap.find(1);
if(iter != idToNameMap.end()) {
idToNameMap.modify(iter, [](auto& p){p->second = "Tom";});
}
以下是另一种方法,您可能会发现更多可发送的(再次,未经测试):
LinkedMap::iterator push_back_or_update(LinkedMap& m,const LinkedMap::value_type& x) {
auto r=m.push_back(x);
if(!r.second) m.replace(r.first, x);
return r.first;
}
答案 1 :(得分:1)
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/tag.hpp>
#include <cassert>
#include <string>
#include <utility>
struct by_key {};
struct by_value {};
template<typename KeyType, typename MappedType>
struct LinkedMap {
using tag_by_key = boost::multi_index::tag<by_key>;
using tag_by_value = boost::multi_index::tag<by_value>;
typedef std::pair<KeyType, MappedType> value_type;
typedef boost::multi_index_container
<
value_type,
boost::multi_index::indexed_by
<
boost::multi_index::random_access<tag_by_value>,
boost::multi_index::ordered_unique
<
tag_by_key,
boost::multi_index::member<value_type, KeyType, &value_type::first>
>
>
> type;
};
int main()
{
LinkedMap<int, std::wstring>::type userMap;
userMap.push_back(std::make_pair(1, L"John"));
// should not overwrite - as per std::map
auto ib = userMap.push_back(std::make_pair(1, L"Tom"));
assert(ib.second == false); // 2nd push_back should fail
auto overwrite = [&](int key, auto&& val)
{
auto& idToNameMap = userMap.get<by_key>();
auto iter = idToNameMap.find(key);
if (iter == idToNameMap.end())
{
auto ib = userMap.push_back(std::make_pair(1, std::forward<decltype(val)>(val)));
assert(ib.second);
}
else
{
idToNameMap.replace(iter,
std::make_pair(key, std::forward<decltype(val)>(val)));
}
};
overwrite(1, L"Tom");
auto& idToNameMap = userMap.get<by_key>();
auto iter = idToNameMap.find(1);
assert(std::wstring(L"Tom") == iter->second);
}