find inside a class if an element exists within a vector of pairs

873 views Asked by At

I'm coding in C++. I have a project with so many files. I have a vector of pairs named list as follows:

std::vector< std::pair< structure1, double> > list;

and I want to check if for a specific double value z , there exists an element: el in the list such that: el.second == z

I want to use find_if

To do so , I've implemented a method : Scheduled that takes two arguments: the first one is an element like those stored in the list , the second one is the specific value to look for. I tried several ways but I end up getting an error always 1st way:

 bool classA::Scheduled(std::pair< structure1,double > const el, double const t )
{
  return el.second==t;

}

inside another method but still in the same class: classA

auto Scheduled1 = std::bind(&classA::Scheduled,this,_1,z);



 bool call=std::find_if(list.begin(),list.end(),Scheduled1)=!list.end();

This solution gives the following error:

 error: ‘Scheduled1’ does not name a type

2nd way: directly using lambda

bool call = std::find_if(list.begin(),list.end(),[this](std::pair<struct1,double> const& el){return el.second==z;})!=list.end();

z is a member variable of classA This second way of coding gives rise to this error:

error: no matching function for call to 

‘find_if(std::vector >::iterator, std::vector >::iterator, classA::method1(int)::__lambda0)’

2

There are 2 answers

3
Praetorian On BEST ANSWER

There's no need to mix bind, bind1st and mem_fun to do this (the latter two are deprecated in C++11); just use a lambda

bool call = std::find_if(list.begin(), list.end(),
                         [this](std::pair< strucure1,double > const& el) {
                           return el.second == z;
                         }) != list.end();

Or if you want to call Scheduled

bool call = std::find_if(list.begin(), list.end(),
                         [this](std::pair< strucure1,double > const& el) {
                           return Scheduled(el, z);
                         }) != list.end();

If you must use bind

bool call = std::find_if(list.begin(), list.end(),
                         std::bind(&classA::Scheduled, this, _1, z)) != list.end();

In either case, you might want to change Scheduled to be a static member function since it doesn't need access to any non-static members, in which case the bind option becomes

bool call = std::find_if(list.begin(), list.end(),
                         std::bind(&classA::Scheduled, _1, z)) != list.end();

Also, Scheduled should probably take the std::pair argument by const& to avoid unnecessary copies.

Another option is to use any_of instead of find_if, which avoids having to compare the result with the end interator

bool call = std::any_of(list.begin(), list.end(),
                        <insert lambda or bind expression>);

Here's an explanation of what's wrong with your attempt.

auto Scheduled1=std::bind(Scheduled, _1, z);

Scheduled is a non-static member function, which means it takes an implicit first argument, a pointer to the instance it must be invoked on, i.e. the this pointer. Moreover, the syntax for creating a pointer to member function is &ClassName::MemberFunctionName. So the above line should be

auto Scheduled1=std::bind(&classA::Scheduled, this, _1, z);

bind returns a function object of unspecified type, but you use that object as if it were a member function (mem_fun(&classA::Scheduled1)) which is clearly incorrect. Simply passing the above Scheduled1 object as the 3rd argument to find_if in your example should work.

0
Werner Erasmus On

As mentioned by @Praetorian, you could've used lambdas. However, binders allow one to use existing predicate functions out of the box, though, and is sometimes more readable (The fact that the new std::bind automatically binds a member function to instance, allows one to use the public interface of a type out of the box). I've added an example similar to yours (that compiles) in which I'll explain some things (see code comments):

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

// Replaces your structure...
struct Xs{};


// typedef so that we can alias the ugly thing...    
typedef std::vector<std::pair<Xs, double>> XDoubleVector;

// --- From your code, I've just named it A for brevity....
struct A
{
    bool Scheduled(std::pair<Xs,double> const el, double const t )
    {
      return el.second==t;
    }
};


int main() {

    using namespace std::placeholders;
    //Instantiate it.... replaced your list.
    XDoubleVector doubleVect;
    //--- and add some elements....

    //We need to instantiate A, in order to invoke 
    // a member function...
    A a;

    // Returns true if found...
    return std::find_if(
        doubleVect.begin(),
        doubleVect.end(),
        //Notes:
        //- Scheduled is a member function of A
        //- For that reason, we need to pass an instance of
        //   A to binder (almost seen as first bound).
        //- _1 indicates that the first parameter to Scheduled will be            
        //   passed in by algorithm
        //- We've hardcoded the second parameter (it is therefore 
        //   bound early).
        std::bind(&A::Scheduled, a, _1, 20.9)) != doubleVect.end();

}

Regards, Werner