如何在 std::tuple 中合并 std::unordered_map?
How to merge std::unordered_map inside std::tuple?
我想创建一个 class,里面有一个 std::tuple
和 std::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);
}
但是我无法编译这段代码。
我尝试用 un std::tuple
of int
创建一个简单的例子,然后对它们求和,结果成功了。但我坚持这个更复杂的例子。
感谢您的任何建议。
试试这个:
#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
不会 return 映射,它会修改第一个。所以我更新了参数和 return 值来反映它。
我看到的更大的问题是 std::unorderd_map<something...>::merge()
return 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;
}
但还要记住包含 <string>
并且 {.data = f}
初始化语法不是 C++17(如果我没记错的话,将从 C++20 开始可用)。
我就是这样解决的。我还使它对 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);
}
我想创建一个 class,里面有一个 std::tuple
和 std::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);
}
但是我无法编译这段代码。
我尝试用 un std::tuple
of int
创建一个简单的例子,然后对它们求和,结果成功了。但我坚持这个更复杂的例子。
感谢您的任何建议。
试试这个:
#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
不会 return 映射,它会修改第一个。所以我更新了参数和 return 值来反映它。
我看到的更大的问题是 std::unorderd_map<something...>::merge()
return 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;
}
但还要记住包含 <string>
并且 {.data = f}
初始化语法不是 C++17(如果我没记错的话,将从 C++20 开始可用)。
我就是这样解决的。我还使它对 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);
}