0

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)’

Praetorian
  • 106,671
  • 19
  • 240
  • 328
Saddam
  • 25
  • 8
  • The type returned from std::bind is not a member function, and Scheduled1 names a value, not a type. – Werner Erasmus May 27 '15 at 13:40
  • For the record, what you're doing is a form of [currying](http://en.wikipedia.org/wiki/Currying) (might make it easier to search for it using that name in some instances). – anthonyvd May 27 '15 at 14:09
  • Sorry, but you're going to have to do better if you want more help. There are several errors in the code you added, and unless you can post valid code, I'm not trying anymore. `&ClassA::IsItScheduled` - the `c` in `classA` is now uppercase? And what is `IsItScheduled`? `...Scheduled1)=!list.end();` - `=!` is obviously incorrect. And in the lambda example, the result of `find_if` is not convertible to `bool`, you need to compare that with the end iterator as you did in the other example. Please create a testcase that I can copy-paste as is, and reproduce the error. See [SSCCE](http://sscce.org) – Praetorian May 27 '15 at 17:18
  • sorry for the errors, I have corrected them all I think, but the errors continue to show up – Saddam May 27 '15 at 21:09
  • @Saddam (you need to use @ when replying so people get notified). I still don't see a testcase I can copy-paste and reproduce the errors you're seeing. Because you're new to SO, [this](http://coliru.stacked-crooked.com/a/430b1cd81b6e02c9) is how you create a testcase. Clearly, both the `bind` and lambda examples work. If you still can't figure it out, create something similar that shows the errors you're seeing. I don't want random snippets of code, I want a complete program that I can copy-paste and compile **as is**. – Praetorian May 27 '15 at 23:47
  • @Praetorian It's a big project, it contains a big number of files (I guess about 60 ) and I was given some files to modify (about 10) but the one that contains the main I'm not supposed to check it, in addition to that, the main calls for so many files before it reaches the files I'm modifying, so it's really difficult to give you a test case and that's why it's complicated for me either, since I don't know all the code of the project, I happened to know only no more than 2000 lines . – Saddam May 28 '15 at 08:20

2 Answers2

4

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.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • Thanks for the explanation, it was clear enough, however, for the two first suggestions , I get this error: error: capture of non variable classA::z For the third one, the compiler displays: Scheduled1 does not name a type the same message as before for the third one here is what I've written bool call = std::find_if(list.begin(),list.end(),Scheduled1)==list.end(); – Saddam May 27 '15 at 15:13
  • @Saddam I didn't realize `z` was a member of `classA`, you need to replace `z` with `this` in the lambda capture list, see updated answer. I'm not sure what the problem is with the other option. `auto Scheduled1 = std::bind(&classA::Scheduled, this, _1, z); std::find_if(list.begin(), list.end(), Scheduled1);` should compile. If you're still having trouble with that, then [edit](https://stackoverflow.com/posts/30483667/edit) the question and add the code that doesn't compile, along with the exact error message. – Praetorian May 27 '15 at 15:58
  • @Praetorian I'm going to do so It's now displaying really weird messages like:error: no matching function for call to ‘find_if(std::vector >::iterator, std::vector >::iterator, ClassA::method1(int)::__lambda0)’ – Saddam May 27 '15 at 16:24
0

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

Werner Erasmus
  • 3,988
  • 17
  • 31