【问题标题】:How to merge std::unordered_map inside std::tuple?如何在 std::tuple 中合并 std::unordered_map?
【发布时间】:2019-07-06 15:57:01
【问题描述】:

我想创建一个类,里面有一个std::tuplestd::unordered_map。 我想创建一个方法来合并元组内的地图。

#include <tuple>
#include <unordered_map>

template <typename ... Ts, std::size_t ... Is>
std::tuple<Ts...> merge_map (std::tuple<Ts...>& t1, std::tuple<Ts...> & t2, std::index_sequence<Is...> const &) { 
    return { 
        (std::get<Is>(t1).merge( std::get<Is>(t2)))... 
    }; 
}

template <class ...Ts>
struct MyContainer
{
    std::tuple<Ts...> data;

    void merge(MyContainer<Ts...>& other){
        data = merge_map(data, other.data, std::make_index_sequence<sizeof...(Ts)>{});
    }

};

int main()
{
    using namespace std;
    unordered_map<string, int> f = {{"zero", 0}, {"one", 1}};
    MyContainer <unordered_map<string, int>> container1 = {.data = f};

    unordered_map<string, int> s = {{"two", 2}, {"three", 3}};
    MyContainer <unordered_map<string, int>> container2 = {.data = s};

    container1.merge(container2);
}

但我无法编译这段代码。 我试图用 int 的 un std::tuple 创建一个简单的例子,然后对它们求和,它起作用了。但我坚持这个更复杂的例子。 感谢您的任何建议。

【问题讨论】:

    标签: c++ c++17 variadic-templates template-meta-programming unordered-map


    【解决方案1】:

    我看到的更大的问题是std::unorderd_map&lt;something...&gt;::merge() 返回void

    肯定是错的

    return { 
        (std::get<Is>(t1).merge( std::get<Is>(t2)))... 
    }; 
    

    我建议修改merge_map(),使用模板折叠,如下

    template <typename ... Ts, std::size_t ... Is>
    std::tuple<Ts...> merge_map (std::tuple<Ts...> & t1,
                                 std::tuple<Ts...> & t2,
                                 std::index_sequence<Is...> const &) { 
       (std::get<Is>(t1).merge(std::get<Is>(t2)), ...); 
    
       return t1;
    }
    

    但还要记住包括 &lt;string&gt; 并且 {.data = f} 初始化语法不是 C++17(如果我没记错的话,将从 C++20 开始提供)。

    【讨论】:

    • 伙计,我不知道在这种情况下如何使用..., ...) 语法纯属疯狂。天才,但疯狂。
    • @RadosławCybulski - 永远不要低估黑暗的力量......嗯嗯......对不起......可变参数模板。
    【解决方案2】:

    试试这个:

    #include <tuple>
    #include <unordered_map>
    #include <iostream>
    
    template <typename T>
    void merge_map_helper (T& t1, T& t2) { }
    template <typename T, std::size_t I, std::size_t ... Is>
    void merge_map_helper (T& t1, T& t2) { 
        std::get<I>(t1).merge( std::get<I>(t2));
        merge_map_helper<T, Is...>(t1, t2);
    }
    
    template <typename ... Ts, std::size_t ... Is>
    void merge_map (std::tuple<Ts...>& t1, std::tuple<Ts...> & t2, std::index_sequence<Is...> const &) { 
        merge_map_helper<std::tuple<Ts...>, Is...>(t1, t2);
    }
    
    template <class ...Ts>
    struct MyContainer
    {
        std::tuple<Ts...> data;
    
        MyContainer(std::tuple<Ts...> data) : data(std::move(data)) { }
    
        void merge(MyContainer<Ts...>& other){
            merge_map(data, other.data, std::make_index_sequence<sizeof...(Ts)>{});
        }
    };
    
    int main()
    {
        using namespace std;
        unordered_map<string, int> f1 = {{"zero1", 0}, {"one", 1}};
        unordered_map<string, int> f2 = {{"zero2", 0}, {"one", 1}};
        MyContainer <unordered_map<string, int>, unordered_map<string, int>> container1 = 
            { { f1, f2 } };
    
        unordered_map<string, int> s1 = {{"two1", 2}, {"three", 3}};
        unordered_map<string, int> s2 = {{"two2", 2}, {"three", 3}};
        MyContainer <unordered_map<string, int>, unordered_map<string, int>> container2 = 
            { { s1, s2} };
    
        container1.merge(container2);
    
        for(auto & k :std::get<0>(container1.data)) {
            std::cout << k.first << " " << k.second << "\n";
        }
    
        for(auto & k :std::get<1>(container1.data)) {
            std::cout << k.first << " " << k.second << "\n";
        }
    }
    

    注意,merge_map 不返回地图,它会修改第一个。所以我更新了参数和返回值来反映它。

    【讨论】:

      【解决方案3】:

      我就是这样解决的。我还让它对 c++14 友好:)

      #include <tuple>
      #include <unordered_map>
      
      
      
      template <typename ... Ts, std::size_t ... Is>
      auto merge_map (std::tuple<Ts...>& t1, std::tuple<Ts...> & t2, std::index_sequence<Is...> const &) { 
          return std::make_tuple( 
              std::get<Is>(t1)..., std::get<Is>(t2)...
          ); 
      }
      
      template <class ...Ts>
      struct MyContainer
      {
          std::tuple<Ts...> data;
      
      };
      
      template <class ...Ts>
      auto merge(MyContainer<Ts...>& c1, MyContainer<Ts...>& c2){
         return merge_map(c1.data, c2.data, std::make_index_sequence<sizeof...(Ts)>{});
      }
      
      int main()
      {
          using namespace std;
          unordered_map<string, int> f = {{"zero", 0}, {"one", 1}};
          MyContainer <unordered_map<string, int>> container1 = {.data = std::make_tuple(f)};
      
          unordered_map<string, int> s = {{"two", 2}, {"three", 3}};
          MyContainer <unordered_map<string, int>> container2 = {.data = std::make_tuple(s)};
      
          MyContainer<decltype(f), decltype(s)> cc;
          cc.data = merge(container1, container2);
      
      }
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-07-09
        • 1970-01-01
        • 1970-01-01
        • 2019-06-15
        • 2016-03-14
        • 1970-01-01
        • 2022-01-11
        • 2021-05-30
        相关资源
        最近更新 更多