c++ - std::reduce 与 std::unordered_map

标签 c++ c++17 unordered-map c++-standard-library

我有一个 vector unordered_map,我正在尝试使用std::reduce来获取所有值的总和 map 中的 vector 。我当前的功能代码(我想替换)如下所示:

// 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;
}

我想用 std::reduce 替换它以利用并行执行;我认为这很简单,因为我只需要用对 std::reduce 的调用替换每个循环,但这似乎不起作用。我的尝试是这样的:

#include <numeric>
#include <execution>
#include <vector>
#include <unordered_map>
#include <cstdint>
// reduces the vectors
template <typename Iter, typename T>
T get_vector_sum(Iter begin, Iter end, T initial = 0)
{
    return std::reduce(std::execution::par_unseq, begin, end, initial, 
           [&](auto cur, auto prev) { return cur + prev; });
}

// calls get_vector_sum for all vectors and then reduces vector sums
template<typename Iter>
uint64_t get_map_sum(Iter begin, Iter end)
{
    return std::reduce(std::execution::par_unseq, begin, end, 0ULL,
            [&](auto prev, auto cur)
            {
                return get_vector_sum<std::vector<uint64_t>::iterator, 
                       uint64_t>(cur.begin(), cur.end(), prev);
                //return get_vector_sum<std::vector<uint64_t>::iterator,
                //       uint64_t>(cur.second.begin(), cur.second.end(), prev);
            });
}

使用上面的代码,我收到一条错误消息,指出 error C2039: 'begin': is not a member of 'std::pair' 引用 auto curget_map_sum 内的 lambda 中。我最初使用 cur 作为 std::pair,但是当我这样做时,我收到了一个不同的错误,指出 error C2228: left of '.second' must have类/结构/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;
}

是否可以将 std::reduce 与这样的 map 一起使用,如果可以,我需要进行哪些更改才能使其正常工作?

最佳答案

请注意 std::reduce binary_op 的此要求:

binary FunctionObject that will be applied in unspecified order to the result of dereferencing the input iterators, the results of other binary_op and init.

这意味着 lambda 结果和 init 的结果需要与映射的值类型具有相同的类型,即 std::pair<const uint64_t, std::vector<uint64_t>>

因此,您需要对此类型的值执行外部归约,这将涉及构建新 vector 。


我还尝试创建示例代码,如下所示:

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

但是由于似乎缺少std::reduce,所以它无法使用GCC 进行编译。实现和 Clang 提示缺少值类型的复制赋值运算符,由于 const 键,该运算符不可复制赋值: https://wandbox.org/permlink/FBYAhCArtOHvwu8C

但是,在cppreference中,对值类型的要求只是MoveConstructible,而不是Copy/MoveAssignable。因此,libc++ 中似乎有一个不正确的实现。


在这个示例代码中,我可以通过定义 V 来使其工作。不带 const 如下:

using V = std::pair<uint64_t, std::vector<uint64_t>>; 

参见https://wandbox.org/permlink/lF9VuJwISYXhpBJL .

关于c++ - std::reduce 与 std::unordered_map,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55096214/

相关文章:

c++ - 在 C++ std::<vector> 容器中存储多种类型结构的模式

c++ - 在已经是模板可变参数的函数中传递可变参数

c++ - 初始化静态 boost::unordered_map

c++ - 错误 : passing ‘const …' ’ as ‘this’ argument of ‘…’ discards qualifiers

c++ - 如何在 Visual Studio 中禁用 Microsoft 对 tchar.h 的修饰?

c++ - nullptr 是如何定义的?

c++ - 如何在 C++ 中减去两个位集

c++17 - 结合 void_t 和 enable_if?

c++ - 为什么我不能用 optional<S> 构造 optional<T> (对于 S!=T)?

c++ - 如何减少 C++ map/unordered_map 容器中查找的分配?