-2

I'm trying to understand the third argument in the remove_if() algorithm. According to the description it should be removed if the function returns true. However the function does not return a bool. What syntax is [](char c)?

Does remove_if() actually remove the element? If so why would you call erase() afterwards.

std::string S("AA BB-4499--5");
auto newEnd = std::remove_if(S.begin(), S.end(), [](char c){return c == ' ' || c == '-';});
S.erase(newEnd, S.end());
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
samsung gather
  • 583
  • 1
  • 4
  • 8
  • 5
    "However the function does not return a bool." Actually, it does. – tkausl Mar 30 '18 at 13:12
  • The code you showed is an example of the [erase remove idiom](https://stackoverflow.com/questions/347441/erasing-elements-from-a-vector) – Cory Kramer Mar 30 '18 at 13:13
  • 2
    Forget cplusplus dot com: it's bad and obsolete. Go and see cppreference.com. That's where the good stuff is. – YSC Mar 30 '18 at 13:25

2 Answers2

2

What syntax is [](char c)?

It is lambda syntax in C++11 and later.

In this case, it is used as a predicate which remove_if calls to decide which elements to remove.

Does remove_if() actually remove the element?

No, it just moves the "removed" elements to the end of the string, and then returns an iterator to the first "removed" element. The subsequent erase() actually removes the elements from the string. This is called the erase-remove idiom.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Eljay
  • 4,648
  • 3
  • 16
  • 27
1

There are two versions of remove (without copy) algorithms. They are

template<class ForwardIterator, class T>
ForwardIterator remove(ForwardIterator first, ForwardIterator last,
const T& value);

and

template<class ForwardIterator, class Predicate>
ForwardIterator remove_if(ForwardIterator first, ForwardIterator last,
Predicate pred);

The first variant of the algorithm "removes" all elements in a container that satisfy the condition *i == value where i is an iterator in the range [first, last).

The second variant of the algorithm "removes" all elements in a container that satisfy the condition pred(*i) != false where i is an iterator in the range [first, last).

In fact the predicate is used in an if statement and its value contextually is converted to the type bool.

The algorithms do not actually remove elements. They move them to the end of the range and return the end of the resulting range that is of the range of actual elements after moving "removed" elements.

Calling the member function erase results in actual removing these elements.

Consider the following demonstrative program.

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

int main() 
{
    std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    auto last = std::remove_if( v.begin(), v.end(), []( int x ) { return x % 2; } );

    for ( int x : v ) std::cout << x << ' ';
    std::cout << std::endl;

    for ( auto first = v.begin(); first != last; ++first )
    {
        std::cout << *first << ' ';
    }

    std::cout << "||| ";

    for ( auto first = last; first != v.end(); ++first )
    {
        std::cout << *first << ' ';
    }

    std::cout << std::endl;

    v.erase( last, v.end() );

    for ( int x : v ) std::cout << x << ' ';
    std::cout << std::endl;

    return 0;
}

Its output is

0 2 4 6 8 5 6 7 8 9 
0 2 4 6 8 ||| 5 6 7 8 9 
0 2 4 6 8 
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335