2017-10-13 45 views
0

我使用multi_index_container来跟踪插入顺序并执行映射工作(如Java的LinkedMap)。如何更新boost multi_index_container的值?

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

测试用例失败。

结果消息:断言失败。预计:<汤姆>实际:<约翰>

这意味着第二个push_back不会更新值。

我的代码有什么问题?我怎么能实现一个LinkedMap?

+0

我很乐意帮助你,但是你的MCVE并不完整。它没有包含头文件。 –

+0

@RichardHodges更新。如果你不使用它,你可以删除CppUnitTestFramework。 – user1633272

回答

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

以下是另一种方式来做到这一点,你可能会发现更多的patalable(再次,未经测试):

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; 
} 
+0

我需要id(1)是唯一的,这意味着第二个条目应该替换第一个条目。这就是我称之为LinkedMap的原因。 – user1633272

+0

只是扩大了我的答案。 –

+0

似乎可行,不知道是否有一个简单的方法来实现它。 – user1633272

1
  • 修复的bug
  • 与断言(这样我就可以测试它
  • 取代Windows的特定测试我的系统)
  • 通过索引视图中添加更换演示
  • 添加标签

 

#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); 
} 
+0

你知道为什么push_back的默认行为不会覆盖退出值吗? – user1633272

+0

@ user1633272,因为'boost :: multi_index :: ordered_unique'建模一个'std :: set',而不是'std :: multi_set',因此不允许添加重复键。 –

相关问题