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());