Возникли проблемы с vector.erase() и remove_if()

До использования remove_if я использовал remove. Скажем, если бы я имел vec = {1, 2, 2, 2, 5} и хотел удалить все 2, я бы сделал:

for (vector<int>::iterator it = vec.begin(); it!= vector.end(); ++it){
    if (*it == 2){
       vec.erase(remove(vec.begin(),vec.end(), *it), vec.end());
    }
}

Это не будет работать, так как невозможно и нелогично перебирать вектор по мере удаления.

Итак, я обнаружил remove_if(). Однако по какой-то причине я не могу заставить его работать в контексте класса. Вот мой код:

class SomeClass{
    private:
       vector<int> vec;
    public:
       SomeClass(){
           //initalizae vec to {1,2,2,2,4,5,6,8}
       }
       bool is_even(int value){
           return value % 2 == 0;
       }
       void delete(int a){
           vec.erase(remove_if(vec.begin(), vec.end(), a), vec.end());
       }
       void delete_even(int a){
           vec.erase(remove_if(vec.begin(), vec.end(), this->is_even(a)), vec.end());
       }

Я предполагаю, что void delete не будет работать, потому что a является int, и мне нужно значение bool, но я не уверен, как выразить "если int a находится в этом векторе, вернуть true" в качестве третьего параметра для remove_if. И я ожидаю, что void delete_even будет работать, но я получаю

note: in instantiation of function template specialization 'std::__1::remove_if<std::__1::__wrap_iter<int *>, bool>' requested here

2 ответа

Решение

Просто используйте std::remove удалить int Значение из коллекции, не ища ее самостоятельно:

vec.erase(std::remove(vec.begin(), vec.end(), 2), vec.end());

Это удалит все случаи 2 от vec,

Использование remove_if то же самое, только тогда, а не элемент, который вы задаете предикату (обычно это функция); если вам доступен C++11, вы можете использовать его с лямбдой как таковой:

vec.erase(std::remove_if(vec.begin(), vec.end(), [](int a) {return a % 2 == 0;}), vec.end());

Если вы хотите использовать is_even в качестве предиката remove_if (или другая функция-член вашего класса), тогда, как уже упоминалось в комментариях, вы должны сделать ее статической функцией-членом, предпочтительно. Вы также можете bind для нестатичных участников, но здесь нет реальной причины делать это; но смотрите Использование std::bind с функцией-членом, использовать указатель на объект или нет для этого аргумента? если вам интересно, сам вопрос содержит правильный синтаксис. Образец для is_even как статический:

 static bool is_even(int value) {
     return value % 2 == 0;
 }

 void delete_even(int a){
     vec.erase(remove_if(vec.begin(), vec.end(), is_even), vec.end());
 }

Если вы просто хотите удалить некоторое значение из вектора, чем вы можете просто использовать remove()

foo.erase(std::remove(foo.begin(), foo.end(), some_value), foo.end());

Если вы хотите удалить все четные числа, то вместо использования функции-члена класса я бы предложил использовать лямбду.

foo.erase(std::remove_if(foo.begin(), foo.end(), [](auto n) { return n % 2 == 0;}), foo.end());

Вот пример, использующий оба подхода

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> foo = {1,2,3,4,5,6,7,8,9};
    // remove all even numbers
    foo.erase(std::remove_if(foo.begin(), foo.end(), [](auto n) { return n % 2 == 0;}), foo.end());
    for (auto e : foo)
        std::cout << e << std::endl;
    std::cout << std::endl;
    // remove all elemenets that match some_value
    foo = {1,2,2,2,2,2,7,8,9};
    int some_value = 2;
    foo.erase(std::remove(foo.begin(), foo.end(), some_value), foo.end());
    for (auto e : foo)
        std::cout << e << std::endl;
}

Выход:

1
3
5
7
9

1
7
8
9

Живой пример

Другие вопросы по тегам