tags:

views:

121

answers:

3

Hi Guys,

Just for fun I was trying to write a one line with std::find_if with boost::bind to check whether all the keys given in a vector in a map has no values, but really could not come up with a neat line of code.
Here is what I attempted

vector<string> v;  
v.push_back("a");  
v.push_back("2");  
...  
map<string, string> m;  
m.insert("b","f");  
...  
std::find_if(v.begin(), v.end(), boost::bind(&string::empty, boost::bind(&map<string,String>::operator[], _1), _2 )) != v.end();  

Obviously this is a big fail... anyone tried something like this?

+5  A: 
std::for_each(v.begin(), v.end(), [](std::string& ref) { if m.find(ref) != m.end() /* do something*/ });

Lambdas ftw.

DeadMG
I do like all the answers-sadly have to choose one over the other. I love lambda's but this time the other answer being more comprehensive gets my vote. :)
SWKK
But his answer wasn't in one line of code!
DeadMG
@DeadMG, your code doesn't even compile because current C++ Standard doesn't support lambda functions.
big-z
@Zilgo: Oh noes, I used a feature available in C++0x. Sue me.
DeadMG
+1  A: 

boost::lambda is your best bet until C++0x where they and other useful mechanisms for functional programming will become a part of the language, but I recommend dumbing down your code a bit if you work in a team.

As short and as concise as such code is, it gives a lot of headaches to less experienced C++ coders who just can't understand functors, predicates, etc. Even among those that do, it can provide headaches trying to debug the code due to its decentralizing nature. I've had to sacrifice all these neater functional aspects of C++ in favor of a simple for loops with iterators just for the overall benefit of the team I work with. Perhaps with C++0x, the issues other programmers have with functional programming might be mitigated enough to where it can be easily understood and without complex template mechanisms that so many people seem to (unfortunately) abhor.

+5  A: 

The following line of code returns true only if all elements from v are not present in m:

bool a = v.end() == std::find_if( v.begin(), v.end(), boost::bind( &str_map_t::const_iterator::operator!=, boost::bind<str_map_t::const_iterator>( &str_map_t::find, &m, _1 ), m.end() ) );

Explanation:

Here we have two functors:

  1. boost::bind<str_map_t::const_iterator>( &str_map_t::find, &m, _1 )
    This functor will return const_iterator which points to the element from m or to m.end() if not found. Here you should explicitly point return type str_map_t::const_iterator for boost::bind to get rid of ambiguity.

  2. boost::bind( &str_map_t::const_iterator::operator!=, _1, _2 )
    This one will return true if _1!=_2 and false otherwise.

Combine 1 and 2 and we'll get the full code:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>
#include <map>    
#include <boost/bind.hpp>    
using namespace std;

int main(int argc, char *argv[])
{
    vector<string> v;
    v.push_back("x");
    v.push_back("a");
    v.push_back("6");

    typedef map<string, string> str_map_t;
    str_map_t m;
    m.insert( str_map_t::value_type( "b", "f" ) );

    bool a = 
      v.end() == std::find_if( 
        v.begin(), v.end(), 
          boost::bind( 
            &str_map_t::const_iterator::operator!=, 
            boost::bind<str_map_t::const_iterator>( &str_map_t::find, &m, _1 ), 
            m.end() 
          ) 
      );

    std::cout << a << endl;

    return 0;
}

I wouldn't say it is readable code and I'd recommend to write a custom functor to get it more readable. A more readable version could look like the following (without bind):

struct not_in_map {
    not_in_map( const str_map_t& map ) : map_(map) {}
    bool operator()( const string& val ) { return map_.end() != map_.find( val ); }
private:
    const str_map_t& map_;
};
bool a = v.end() == std::find_if( v.begin(), v.end(), not_in_map(m) );
Kirill V. Lyadvinsky
Yes, I wont let such code get to see the daylight but still want to learn these nifty features. Thanks for a great answer.
SWKK