0

I try to use find_if to find a key in a map by its value. But I can't compile the code:

struct IsCurrency : binary_function<pair<const Bill::CodeCurrency, string>, string, bool> {
    bool isCurrency(const pair<const Bill::CodeCurrency, string>& element, const string& expected) const {
        return element.second == expected;
    }
};

string currency = "RUB";
map<Bill::CodeCurrency, string>::const_iterator my_currency = find_if(Bill::currency_code_map().begin(), Bill::currency_code_map().end(), bind2nd(IsCurrency(), currency));  /// <--- ERROR IS HERE

Bill::CodeCurrency is an enum.

error:

/usr/include/c++/4.7/bits/stl_algo.h:4490:41:   required from ‘_IIter std::find_if(_IIter, _IIter, _Predicate) [with _IIter = std::_Rb_tree_const_iterator<std::pair<const Bill::CodeCurrency, std::basic_string<char> > >; _Predicate = std::binder2nd<IsCurrency>]’
../src/money_acceptor/itl_bill_acceptor.cpp:182:121:   required from here
/usr/include/c++/4.7/backward/binders.h:155:29: error: no match for call to ‘(const IsCurrency) (const first_argument_type&, const second_argument_type&)’

Could you please help me to determine what's the error here?

Arks
  • 569
  • 5
  • 19
  • 1
    1) The code is formatted horribly (well I've seen worse, but a > 190 char long line?) 2) using deprecated StdLib entities (such as `binary_function`) 3) your problem is that `isCurrency` should be an `operator()` -> [compiles then](http://coliru.stacked-crooked.com/a/3a37628bdcddd864) – dyp Apr 09 '14 at 12:41
  • A bit more context would be useful. It's difficult to tell from your example whether `Bill` is a namespace or a class, for example. – Edward Apr 09 '14 at 12:41

2 Answers2

0

Replace bool isCurrency(...) by bool operator () (...) to make your structure callable.

0

As described in my comment, the actual problem is that the predicate provided to find_if is required to have an operator(), not some function with a name similar to the class name.

C++03 version:

#include <map>
#include <functional>
#include <string>
#include <algorithm>

namespace Bill
{
    enum CodeCurrency
    {
        A, B, C
    };

    typedef std::map<CodeCurrency, std::string> currency_code_map_t;
    currency_code_map_t const& currency_code_map()
    {
        static currency_code_map_t m;
        return m;
    }
}

struct IsCurrency
    : std::binary_function< Bill::currency_code_map_t::value_type, std::string,
                            bool >
{
    bool operator()(Bill::currency_code_map_t::value_type const& element,
                    std::string const& expected) const
    {
        return element.second == expected;
    }
};

int main()
{
    std::string currency = "RUB";
    Bill::currency_code_map_t::const_iterator my_currency =
        std::find_if( Bill::currency_code_map().begin(),
                      Bill::currency_code_map().end(),
                      bind2nd(IsCurrency(), currency) );
}

C++11 version:

#include <map>
#include <functional>
#include <string>
#include <algorithm>

namespace Bill
{
    enum CodeCurrency
    {
        A, B, C
    };

    typedef std::map<CodeCurrency, std::string> currency_code_map_t;
    currency_code_map_t const& currency_code_map()
    {
        static currency_code_map_t m;
        return m;
    }
}

int main()
{
    std::string currency = "RUB";
    auto check = [&currency](Bill::currency_code_map_t::value_type const& element)
                 { return element.second == currency; };
    auto my_currency =
        std::find_if( Bill::currency_code_map().cbegin(),
                      Bill::currency_code_map().cend(),
                      check );
}

Note this algorithm is O(N). You might want to consider using something like a boost::bimap if you need to find elements often, which can be O(logN).

dyp
  • 38,334
  • 13
  • 112
  • 177