Search code examples
c++lambda

C++: Removing elements from the using lambda function with 2 parameters


I have the following predefined lambda function:

auto condition = ParseCondition(is);
auto predicate = [condition](const Date& date, const string& event) {
    return condition->Evaluate(date, event);

What it does:

  1. It takes string stream input and parses it into condition.
  2. Lambda function takes this condition and compares it with date and event and returns true/false based on some condition.

I want to create a function, which uses `predicate, to delete elements from my map object.

My map object is map <Date,std::vector<std::string>> db;

I came up with the following idea:

for(auto &item : db){
     auto& date = item.first;
     auto& events = item.second;
     auto to_remove = std::remove_if(events.begin(),events.end(), predicate);
     events.erase(to_remove,events.end());
}

But the problem here is predicate, which must take 2 parameters: Date and event and I don't know how would I put Date into remove_if. How should I do it?


Solution

  • Use std::bind_front if you have c++20, and use std::cref to avoid copying date.

    for(auto &item : db){
         auto& date = item.first;
         auto& events = item.second;
         auto to_remove = std::remove_if(events.begin(),events.end(), std::bind_front(predicate, std::cref(date));
         events.erase(to_remove,events.end());
    }
    

    If you don't have c++20, since you are using lambdas, you clearly have c++11, and you can use std::bind.

    for(auto &item : db){
         using namespace std::placeholders;
         auto& date = item.first;
         auto& events = item.second;
         auto to_remove = std::remove_if(events.begin(),events.end(), std::bind(predicate, std::cref(date), _1);
         events.erase(to_remove,events.end());
    }
    

    Note that many people advise against using std::bind because the syntax is not that intuitive and there's basically nothing that it can do but a lambda cannot. For more complex situations a lambda is usually clearer. In simple cases where std::bind_front and std::bind_back(in C++23) applies, bind-based solutions still have the advantage of being less verbose without loss of clarity. Another major difference is that with bind functions the callable is stored in the bind object and care must be taken if copying the callable is expensive. On the other hand, a lambda solution encodes the operation in it's type and the callable does not need to be copied or moved around.