Search code examples
c++dictionarystlfindstl-algorithm

Why using find_if like this fail?


I want to find the first nonzero element from a map, therefore I did the following code:

#include <map>
#include <iostream>
#include <algorithm>

bool nonzero(std::map<char,int>::const_iterator& it);

int main()  {
    std::map<char, int> m;
    m['a'] = 0;
    m['b'] = 1;
    std::map<char,int>::iterator it = std::find_if(m.begin(), m.end(), nonzero);
    std::cout << it->first << '\t' << it->second << std::endl;
    return 0;
}


bool nonzero(std::map<char,int>::const_iterator& it)    {
    return it->second;
}

The g++ give errors that is very complicated, saying that:

/usr/include/c++/5/bits/predefined_ops.h:234:30: error: invalid initialization of reference of type ‘std::_Rb_tree_const_iterator<std::pair<const char, int> >&’ from expression of type ‘std::pair<const char, int>’
  { return bool(_M_pred(*__it)); }

I don't understand what does it saying and why my program will fail.


Solution

  • The type expected for your nonzero function called by find_if is not a std::map<char,int>::const_iterator&, but a const std::pair<const char, int> &.

    In fact, if you check some online documentation for find_if, you'll see that the unary predicate has the form:

    bool UnaryPredicate(const Type&)
    

    where Type is in your case std::pair<const char, int> (for a general std::map<Key, Value>, the type is std::pair<const Key, Value>).

    So you may adjust your function passing a const& to that std::pair:

    bool nonzero(const std::pair<const char, int> & p)
    {
        return (p.second != 0);
    }
    

    Note that using C++14 auto with lambdas would have simplified your code, e.g.:

    auto it = std::find_if(m.begin(), m.end(), [](const auto& p){
        return (p.second != 0);
    });
    

    Note also that the pair is of the general form std::pair<const Key, Value> (not just pair<Key, Value> with non-const Key).