c ++ boost условно удалить из контейнера - PullRequest
1 голос
/ 29 июня 2010

я хочу сделать что-то вроде стиля c # linq:

SomeColection <SomeType> someColection;
someColection.Remove(something => something > 2);

и он удалит все, что больше 2 (или любого другого логического условия) ...

используя повышение в проекте ...

Ответы [ 4 ]

5 голосов
/ 29 июня 2010

C ++ 0x (с использованием лямбды):

container.erase( std::remove_if( container.begin(), container.end(), 
                                 []( int v ) { return v > 2; } ),
                 container.end() );

Причина erase в сочетании с remove_if заключается в том, что алгоритмы STL применяются к итераторам, а не к контейнерам. Они перемещают содержимое контейнера, но не изменяют контейнер как таковой.

C ++ 03:

container.erase( std::remove_if( container.begin(), container.end(), 
                                 std::bind2nd( std::greater<int>(), 2 ) ),
                 container.end() );

Это может показаться немного более простым, но также менее гибким, так как предикаты уже определены. Для более сложных операций вам придется написать собственный функтор предикатов.

5 голосов
/ 29 июня 2010

Вам не нужно форсировать (если вы не сфокусированы на встроенной анонимной функции). Обычный STL в порядке.

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

int main () {
        std::vector<int> x (24);
        for (int i = 0; i < x.size(); ++ i)
                x[i] = i % 5;

        std::vector<int>::iterator
          new_end = std::remove_if(x.begin(), x.end(),
                                   std::bind2nd(std::greater<int>(), 2));
        x.erase(new_end, x.end());

        for (int i = 0; i < x.size(); ++ i)
                std::cout << x[i] << " ";

        return 0;
}

С помощью boost вы можете заменить bind2nd на

#include <boost/lambda/lambda.hpp>

...

    using boost::lambda::_1;
    std::vector<int>::iterator new_end = std::remove_if(x.begin(), x.end(), _1 > 2);
4 голосов
/ 29 июня 2010

Во-первых, вам нужна простая оболочка для шаблона:

template <class Container, class UnaryPredicate>
void erase_if(Container& container, UnaryPredicate pred)
{
  container.erase(
    std::remove_if(container.begin(), container.end(), pred),
    container.end()
  );
}

Это хорошо известная идиома, однако это невозможно с map или set, поскольку они поддерживают свой собственный порядок.

Затем вы можете использовать Boost.Lambda , чтобы получить синтаксис, который вы хотите написать сам предикат.

using boost::lambda::_1;

SomeCollection<Type> someCollection;

erase_if(someCollection, _1 > 2);
1 голос
/ 22 января 2018

Кстати, boost :: range v.1.46.0 (выпущенный в 2011 году) имеет именно то, что вы хотите - алгоритм remove_erase_if

#include <boost/range/algorithm_ext/erase.hpp

std::vector<int> vec = {1, 6, 2, 7};
boost::range::remove_erase_if(vec, [](int val){return val > 5;});

Коротко и просто.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...