std:: накапливается с использованием представления std::диапазоны:: представления:: значения

#c #algorithm #range #c 20

#c #алгоритм #диапазон #c 20

Вопрос:

Есть ли какой-либо способ скомпилировать этот код, или я должен создать свой собственный лямбда-код в качестве четвертого параметра 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 выдает, если я правильно понял, в основном говорит, что begin и end выдает разные типы и 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;
      |                                                                 ^

  

Ответ №1:

Ошибка, которую выдает gcc, если я правильно понял, в основном говорит об этом begin и end выдает разные типы

Действительно. С точки зрения диапазонов, elements_view iterator и sentinel являются разными типами. До C 20 эти типы должны были быть одинаковыми, и с учетом этого было написано много кода. К сожалению, у нас пока нет ranges::accumulate того, который бы справился с этим должным образом для вас.

До тех пор существует другой адаптер диапазона, который заставляет диапазон иметь тот же тип для его iterator и sentinel (или быть неоперабельным, если это уже так): views::common :

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

Которое в этом случае создало бы представление common_iterator s, которое в основном variant<iterator, sentinel> обернуто, чтобы вести себя как итератор.

Комментарии:

1. rv::common Имеет ли какое-либо ограничение во время выполнения, это просто адаптер типа во время компиляции или он применяет какой-либо метод удаления типа для адаптации типа?

2. @Peregring-lk Да, как я уже сказал, это в основном вариант. Таким образом, сравнение итератора немного дороже.

3. По какой-то причине мои глаза пропустили эту последнюю строку. Еще раз спасибо.