Почему идиома удаления-удаления не работает для обратного итератора - PullRequest
0 голосов
/ 01 мая 2018

Моя цель состояла в том, чтобы попытаться найти решение этого вопроса: Удаление всех пустых элементов в векторе с конца . используя erase-remove идиома.

Идея состоит в том, чтобы удалить все элементы, начиная с конца, которые являются пустыми (равными пробелу) в данном std::vector<std::string> строках. Удаление элементов должно прекратиться, когда будет найден непустой элемент.

Пример:

vec = { " ", "B", " ", "D", "E", " ", " ", " " };

После удаления:

vec = { " ", "B", " ", "D", "E"};

Вот решение, которое я попробовал:

#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>

int main()
{
    std::vector<std::string> vec = { " ", "B", " ", "D", "E", " ", " ", " " };

    bool notStop = true;
    auto removeSpaceFromLast = [&](const std::string& element)-> bool
    {
        if(element != " " ) notStop = false;
        return ( (element == " ") && (notStop) );
    };

    vec.erase(
        std::remove_if(vec.rbegin(), vec.rend(), removeSpaceFromLast),
            vec.rend() );

    std::copy(vec.begin(), vec.end(), std::ostream_iterator<std::string>(std::cout,","));

    return 0;
}

Это дало мне ошибку:

no matching function for call to  std::vector<std::__cxx11::basic_string<char> >::erase(std::reverse_iterator<__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > > >, std::vector<std::__cxx11::basic_string<char> >::reverse_iterator)'|

Тогда я прочитал о работе std::vector::erase() здесь: Не работает ли vector :: erase с обратными итераторами?

И изменил код:

vec.erase(
    std::remove_if(vec.rbegin().base(), vec.rend().base(), removeSpaceFromLast),
        vec.rend().base() );

На этот раз он скомпилирован, но дал мне вывод = оригинальный вектор.

Может кто-нибудь объяснить:

  1. Почему это случилось?
  2. Если это возможно, как мы можем это исправить?

1 Ответ

0 голосов
/ 01 мая 2018

Вы пропустили звонки на base(). remove_if переместит все найденные пробелы, начиная с конца, в начальную часть вектора (как при перемещении найденных пробелов, начиная с начала, переместится в конец, если использовались прямые итераторы) и вернет итератор, указывающий на конечную позицию последовательности, которая должна быть стерта (т. е. начало пространства, которое будет сохранено, когда мы изменили значения итератора), то есть:

" ", " ", " ", "B", " ", "D", "E"

Затем вы должны стереть с самого начала, т.е. rend().base().

vec.erase(vec.rend().base(), 
          std::remove_if(vec.rbegin(), vec.rend(), removeSpaceFromLast).base()
);
...