【问题标题】:std::accumulate using the view std::ranges::views::valuesstd::accumulate 使用视图 std::ranges::views::values
【发布时间】:2020-09-03 20:13:12
【问题描述】:

有什么方法可以编译该代码,或者我必须创建自己的 lambda 作为std::accumulate 的第四个参数?

#include <iostream>
#include <ranges>
#include <unordered_map>
#include <numeric>

namespace rv = std::ranges::views;

int main()
{
    std::unordered_map<unsigned, unsigned> m = {{5, 3}};
    
    auto values = m | rv::values;
    
    std::cout << std::accumulate(values.begin(), values.end(), 0) << std::endl;
}

gcc 抛出的错误,如果我理解正确的话,基本上是说beginend 产生不同的类型,std::accumulate 不能推断出唯一的InputIterator 类型。完整的编译器输出是:

main.cpp:15:65: error: no matching function for call to 'accumulate(std::ranges::elements_view<std::ranges::ref_view<std::unordered_map<unsigned int, unsigned int> >, 1>::_Iterator<true>, std::__detail::_Node_iterator<std::pair<const unsigned int, unsigned int>, false, false>, int)'
   15 |     std::cout << std::accumulate(values.begin(), values.end(), 0) << std::endl;
      |                                                                 ^
In file included from /usr/local/include/c++/10.2.0/numeric:62,
                 from main.cpp:5:
/usr/local/include/c++/10.2.0/bits/stl_numeric.h:134:5: note: candidate: 'template<class _InputIterator, class _Tp> constexpr _Tp std::accumulate(_InputIterator, _InputIterator, _Tp)'
  134 |     accumulate(_InputIterator __first, _InputIterator __last, _Tp __init)
      |     ^~~~~~~~~~
/usr/local/include/c++/10.2.0/bits/stl_numeric.h:134:5: note:   template argument deduction/substitution failed:
main.cpp:15:65: note:   deduced conflicting types for parameter '_InputIterator' ('std::ranges::elements_view<std::ranges::ref_view<std::unordered_map<unsigned int, unsigned int> >, 1>::_Iterator<true>' and 'std::__detail::_Node_iterator<std::pair<const unsigned int, unsigned int>, false, false>')
   15 |     std::cout << std::accumulate(values.begin(), values.end(), 0) << std::endl;
      |                                                                 ^
In file included from /usr/local/include/c++/10.2.0/numeric:62,
                 from main.cpp:5:
/usr/local/include/c++/10.2.0/bits/stl_numeric.h:161:5: note: candidate: 'template<class _InputIterator, class _Tp, class _BinaryOperation> constexpr _Tp std::accumulate(_InputIterator, _InputIterator, _Tp, _BinaryOperation)'
  161 |     accumulate(_InputIterator __first, _InputIterator __last, _Tp __init,
      |     ^~~~~~~~~~
/usr/local/include/c++/10.2.0/bits/stl_numeric.h:161:5: note:   template argument deduction/substitution failed:
main.cpp:15:65: note:   deduced conflicting types for parameter '_InputIterator' ('std::ranges::elements_view<std::ranges::ref_view<std::unordered_map<unsigned int, unsigned int> >, 1>::_Iterator<true>' and 'std::__detail::_Node_iterator<std::pair<const unsigned int, unsigned int>, false, false>')
   15 |     std::cout << std::accumulate(values.begin(), values.end(), 0) << std::endl;
      |                                                                 ^

【问题讨论】:

    标签: c++ algorithm range c++20


    【解决方案1】:

    gcc 抛出的错误,如果我理解正确的话,基本上是说beginend 产生不同的类型

    确实如此。在 Ranges 术语中,elements_viewiteratorsentinel 是不同的类型。在 C++20 之前,这些类型必须相同,并且在此前提下编写了大量代码。不幸的是,我们还没有ranges::accumulate 可以为您妥善处理。

    在此之前,还有另一个范围适配器强制范围为其iteratorsentinel 具有相同的类型(如果已经是这种情况,则为无操作):views::common

    auto values = m | rv::values | rv::common;
    

    在这种情况下,这将创建一个 common_iterators 的视图,它基本上是一个 variant&lt;iterator, sentinel&gt; 包裹起来以表现得像一个迭代器。

    【讨论】:

    • rv::common 是否在执行时间上有任何损失,它只是一个编译时类型适配器,还是应用任何类型的类型擦除技术来适应类型?
    • @Peregring-lk 是的,就像我说的,它基本上是一个变体。所以迭代器比较稍微贵一点。
    • 呃,我的眼睛不知为何跳过了最后一行。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 2022-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多