Philip Stuyck
Philip Stuyck

Reputation: 7457

find_if on vector<Message*> with bind2nd and functor

I have a vector like this :

typedef vector<Message*> OmciMessages;
OmciMessages omciResponses;

And I have a functor like following which I suspect is not correct :

class isMatching{
public:
    bool operator()(const Message* responseMsg,unsigned short transactionid){       
        return responseMsg->getTransactionId()==transactionid;
    }
};

then I call find_if and want to use the functor to find something in the vector but only for a specific transactionid that is inside my class :

OmciMessages::iterator responseit 
    = find_if(omciResponses.begin(),
              omciResponses.end(),
              bind2nd(isMatching(),transactionid));

The compiler does not like it and spawns quite a lot of error messages that are hard to interpret typically for template classes.

/repo/stuyckp/ngpon2WW/tools/cm4/tools/GNU/src/gcc/i686-pc-linux-gnu/bin/../lib/gcc/i686-pc-linux-gnu/3.4.6/../../../../../include/c++/3.4.6/bits/stl_function.h:429: error: no type named `first_argument_type' in `class isMatching'

It worked if I did it like this without a function object :

static bool isMatching(Message* responseMsg){
    return responseMsg->getTransactionId()==transactionid;
}

transactionid = 5; //global variable being used. yuck, don't like it
find_if(omciResponses.begin(),
        omciResponses.end(),
        isMatching);

but then I needed a global variable transaction id that was set beforehand which I think is not that good a design. So how is this supposed to be done with the bind2nd approach ?

Upvotes: 3

Views: 266

Answers (3)

Piotr Skotnicki
Piotr Skotnicki

Reputation: 48447

struct isMatching
{
    unsigned short transactionid;

    explicit isMatching(unsigned short transactionid) : transactionid(transactionid) {}

    bool operator()(const Message* responseMsg) const
    {       
        return responseMsg->getTransactionId() == transactionid;
    }
};

std::find_if(omciResponses.begin()
           , omciResponses.end()
           , isMatching(0));
//                      ^ transactionId to be searched for

DEMO

Note that if you urge to use std::bind2nd, or the function object would be stateless, then you don't need a function object as a separate class at all:

bool isMatching(const Message* responseMsg, unsigned short transactionid)
{
    return responseMsg->getTransactionId() == transactionid;
}

std::find_if(omciResponses.begin()
           , omciResponses.end()
           , std::bind2nd(std::ptr_fun(&isMatching), 0));
//                        ~~~~~~~~~~~^               ^ transactionId to be searched for
//      transform to a function object

DEMO 2

Upvotes: 1

songyuanyao
songyuanyao

Reputation: 172894

bind2nd needs your functor class to be adaptable, i.e. provide certain typedefs, including first_argument_type, second_argument_type, and result_type. You can define them by yourself in the functor classes, or inherit from std::binary_function to make it easy:

class isMatching : public std::binary_function<const Message*, unsigned short, bool> {
public:
    bool operator()(const Message* responseMsg, unsigned short transactionid) const {       
        return responseMsg->getTransactionId() == transactionid;
    }
};

Upvotes: 2

T.C.
T.C.

Reputation: 137320

Given the version of your compiler, I assume that C++11 is not an option (otherwise the answer is simple: use a lambda).

The old function object binders (deprecated in C++11, removed in C++17) require a bunch of nested typedefs. You need to define result_type, first_argument_type, and second_argument_type as members of isMatching, either directly or via the binary_function helper (which is also deprecated in C++11 and removed in C++17), to use it with bind2nd.

You can also use a plain function taking two arguments, adapt it with ptr_fun (again, deprecated in C++11 and removed in C++17), and then bind with bind2nd.

Or just use a stateful functor, as shown in Piotr's answer.

Upvotes: 2

Related Questions