Как использовать std ::partial_sum и выводить в std::map?

#c #c 11 #stdmap

#c #c 11 #stdmap

Вопрос:

Мне нужна карта вывода, которая имеет { {0,1},{1,2},{2,3},{3,4},{4,5} }, только c 11. Есть идеи?

 std::map<int, int> m, out;
for( auto i=0; i < 5;   i ) 
    m[i] = 1;

std::partial_sum( m.begin(), m.end(), std::inserter( out, out.begin() ),
        []( const std::pair<int,int>amp; a, const std::pair<int,int>amp; b ) 
             { return std::pair<int,int>( a.first, a.second   b.second ); } 
);
 

Это приводит к ошибке компиляции:

 /usr/include/c  /5/bits/stl_pair.h: In instantiation of ‘std::pair<_T1, _T2>amp; std::pair<_T1, _T2>::operator=(std::pair<_U1, _U2>amp;amp;) [with _U1 = int; _U2 = int; _T1 = const int; _T2 = int]’:
/usr/include/c  /5/bits/stl_numeric.h:295:12:   required from ‘_OutputIterator std::partial_sum(_InputIterator, _InputIterator, _OutputIterator, _BinaryOperation) [with _InputIterator = std::_Rb_tree_iterator<std::pair<const int, int> >; _OutputIterator = std::insert_iterator<std::map<int, int> >; _BinaryOperation = main()::<lambda(const std::pair<int, int>amp;, const std::pair<int, int>amp;)>]’
../src/test_cumsum.cpp:43:130:   required from here
/usr/include/c  /5/bits/stl_pair.h:188:10: error: assignment of read-only member ‘std::pair<const int, int>::first’
first = std::forward<_U1>(__p.first);
 

Ответ №1:

Вы не можете. По крайней мере, не напрямую. Проблема в том, что std::map<int, int>::iterator::value_type есть std::pair<const int, int> , и это const предотвращает присвоение объекту этого типа.

Взгляните на эту возможную реализацию для std::partial_sum :

 template<class InputIt, class OutputIt, class BinaryOperation>
constexpr // since C  20
OutputIt partial_sum(InputIt first, InputIt last, 
                     OutputIt d_first, BinaryOperation op)
{
    if (first == last) return d_first;
 
    typename std::iterator_traits<InputIt>::value_type sum = *first;
    *d_first = sum;
 
    while (  first != last) {
       sum = op(std::move(sum), *first); // std::move since C  20
       *  d_first = sum;
    }
    return   d_first;
}
 

Обратите внимание, что это sum изменяется на каждой итерации путем присвоения результата op . Потому sum.first const что это невозможно; отсюда ошибка компиляции.

Что вы могли бы сделать, это определить тип итератора, который переносит std::map::iterator и удаляет const . Например, будет работать следующее:

 template <typename Pair>
struct RemoveFirstConstHelper
{
    using type = Pair;
};

template <typename T1, typename T2>
struct RemoveFirstConstHelper<std::pair<const T1, T2>>
{
    using type = std::pair<T1, T2>;
};

template <typename MapIterator>
class RemoveFirstConstIter
{
public:
    using difference_type = std::ptrdiff_t;
    using value_type = typename RemoveFirstConstHelper<typename MapIterator::value_type>::type;
    using pointer = value_type*;
    using reference = value_type;
    using iterator_category = std::input_iterator_tag;
    
    RemoveFirstConstIter(MapIterator it) : it_{it} {}
    
    reference operator*()
    {
        return *it_;
    }
    
    RemoveFirstConstIteramp; operator  ()
    {
          it_;
        return *this;
    }
    
    RemoveFirstConstIter operator  (int) const
    {
        RemoveFirstConstIter temp{*this};
          temp;
        return temp;
    }
    
    bool operator==(const RemoveFirstConstIteramp; other) const
    {
        return it_ == other.it_;
    }
    
    bool operator!=(const RemoveFirstConstIteramp; other) const
    {
        return !(*this == other);
    }
    
private:
    MapIterator it_;
};
 

Живая демонстрация

Или вы могли бы просто написать свою собственную partial_sum реализацию для maps. Мне кажется, что это было бы проще.

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

1. спасибо за ответ. Теперь я вижу, что ключи не могут быть изменены в map, отсюда и ошибка. Сложнее, чем я думал.

2. Хорошо отформатированный ответ с хорошими цитатами. Молодец.