C++ std::reduce与std::无序_映射
我有一个C++ std::reduce与std::无序_映射,c++,c++17,unordered-map,c++-standard-library,C++,C++17,Unordered Map,C++ Standard Library,我有一个无序的
无序的
的向量
,我试图使用std::reduce
来获得映射中所有向量中所有值的总和。我当前的功能代码(我要替换)如下所示:
// input is std::unordered_map<std::vector<uint64_t>>
template<typename T>
uint64_t get_map_sum(T& my_map)
{
uint64_t totalcount = 0;
for (auto& p : my_map)
{
for (const auto& q : p.second)
totalcount += q;
}
return total_count;
}
使用上面的代码,我收到一条错误消息,说error C2039:'begin':不是'std::pair'的成员。
指的是内部lambda中的auto cur
。我最初使用cur
作为std::pair
,但当我这样做时,我得到了一个不同的错误,即error C2228:left of'.second'必须具有class/struct/union
int main()
{
std::unordered_map<uint64_t, std::vector<uint64_t>> in({
{1, std::vector<uint64_t>{1,2,3,4,5} },
{2, std::vector<uint64_t>{1,2,3,4,5}},
{3, std::vector<uint64_t>{1,2,3,4,5}}});
auto x = get_map_sum(in); // output 45
auto y = get_map_sum(in.begin(), in.end()); // error
return 0;
}
intmain()
{
({
{1,std::vector{1,2,3,4,5},
{2,std::vector{1,2,3,4,5},
{3,std::vector{1,2,3,4,5}}});
auto x=get_map_sum(in);//输出45
自动y=get_map_sum(in.begin(),in.end());//错误
返回0;
}
可以将std::reduce
与这样的映射一起使用吗?如果可以,我需要做哪些更改才能使其正常工作?请注意以下二进制操作的要求:
二进制函数对象,该对象将按未指定的顺序应用于取消引用输入迭代器的结果、其他二进制函数的结果和init
这意味着lambda result和init的结果需要与map的值类型具有相同的类型,即std::pair
因此,您需要对这种类型的值执行外部缩减,这将涉及构造新的向量
我还尝试创建一个示例代码,如下所示:
using M = std::unordered_map<uint64_t, std::vector<uint64_t>>;
using V = M::value_type;
M in({ {1, std::vector<uint64_t>{1,2,3,4,5}},
{2, std::vector<uint64_t>{1,2,3,4,5}},
{3, std::vector<uint64_t>{1,2,3,4,5}} });
auto p = std::reduce(in.begin(), in.end(), V{},
[](const V& a, const V& b) {
auto ra = std::reduce(a.second.begin(), a.second.end(), 0UL,
[](uint64_t i1, uint64_t i2){ return i1 + i2; });
auto rb = std::reduce(b.second.begin(), b.second.end(), 0UL,
[](uint64_t i1, uint64_t i2){ return i1 + i2; });
return V{0, { ra + rb }};
});
using V = std::pair<uint64_t, std::vector<uint64_t>>;
请参阅。我们不需要构建向量作为中间结果,而只需要提供一个从M::value\u type
隐式转换的类型
using M = std::unordered_map<uint64_t, std::vector<uint64_t>>;
template <typename Iter, typename T>
T par_unseq_sum(Iter begin, Iter end, T initial = 0)
{
// std::plus is the default reducer
return std::reduce(std::execution::par_unseq, begin, end, initial);
}
class map_vector_sum
{
public:
map_vector_sum() : sum(0) {}
map_vector_sum(M::const_reference elem) : sum(par_unseq_sum(elem.second)) {}
map_vector_sum& operator+(const map_vector_sum & rhs) { sum += rhs.sum; }
explicit operator uint64_t() { return sum; }
private:
uint64_t sum;
}
M in({ {1, std::vector<uint64_t>{1,2,3,4,5}},
{2, std::vector<uint64_t>{1,2,3,4,5}},
{3, std::vector<uint64_t>{1,2,3,4,5}} });
uint64_t sum = par_unseq_sum(in.begin(), in.end(), map_vector_sum());
使用M=std::无序映射;
模板
T par_unseq_sum(Iter开始,Iter结束,T初始=0)
{
//std::plus是默认的减速机
返回std::reduce(std::execution::par_unseq、begin、end、initial);
}
类映射\向量\和
{
公众:
map_vector_sum():sum(0){}
映射向量和(M::常数参考元素):和(第二元素)
map_vector_sum&运算符+(const map_vector_sum&rhs){sum+=rhs.sum;}
显式运算符uint64_t(){返回和;}
私人:
uint64_t sum;
}
M in({1,std::vector{1,2,3,4,5}}),
{2,std::vector{1,2,3,4,5},
{3,std::vector{1,2,3,4,5}}});
uint64_t sum=par_unseq_sum(in.begin()、in.end()、map_vector_sum());
我试图让您在coliru或godbolt中跑步,但失败了。如果没有#include
,std::reduce
,则无法识别(#include
)没有帮助。使用#include
,编译器拒绝,因为它没有找到它。@如果您是对的,那些联机编译器不完全支持C++17。但是你提到的include是唯一需要的,我也把它们添加到了我的问题中。哦,那么未指定的顺序是指参数,而不是输入值?我认为这意味着它可能会洗牌输入值,但它仍将始终使用前一次调用(或第一次调用init)的结果调用二进制函数,然后从输入迭代器调用一个元素。也就是说,像这样的F(…F(F(init,*it++),*it++…)@nick,缩减操作需要能够对两个映射元素(键值对)执行二进制运算,然后对其原始应用程序的结果执行完全相同的操作。因此,结果必须具有完全相同的类型。顺便说一句,见更新的答案,我添加了一个工作示例。尽管我怀疑它在遗传上是否有效,因为需要构建许多新的向量,这涉及到动态内存分配。
using M = std::unordered_map<uint64_t, std::vector<uint64_t>>;
template <typename Iter, typename T>
T par_unseq_sum(Iter begin, Iter end, T initial = 0)
{
// std::plus is the default reducer
return std::reduce(std::execution::par_unseq, begin, end, initial);
}
class map_vector_sum
{
public:
map_vector_sum() : sum(0) {}
map_vector_sum(M::const_reference elem) : sum(par_unseq_sum(elem.second)) {}
map_vector_sum& operator+(const map_vector_sum & rhs) { sum += rhs.sum; }
explicit operator uint64_t() { return sum; }
private:
uint64_t sum;
}
M in({ {1, std::vector<uint64_t>{1,2,3,4,5}},
{2, std::vector<uint64_t>{1,2,3,4,5}},
{3, std::vector<uint64_t>{1,2,3,4,5}} });
uint64_t sum = par_unseq_sum(in.begin(), in.end(), map_vector_sum());