пытаясь увидеть, нет ли вектора <string>значений в карте <строка, строка> - PullRequest
3 голосов
/ 24 июня 2010

Просто для удовольствия я пытался написать одну строку с std :: find_if с boost :: bind, чтобы проверить, не имеют ли все ключи, данные в векторе на карте, никаких значений, но на самом деле не могли придумать аккуратныйстрока кода.
Вот то, что я пытался

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();  

Очевидно, что это большой провал ... кто-нибудь пробовал что-то подобное?

Ответы [ 3 ]

5 голосов
/ 24 июня 2010

Следующая строка кода возвращает true, только если все элементы из v отсутствуют в 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() ) );

Пояснение:

Здесь у нас есть два функтора:

  1. boost::bind<str_map_t::const_iterator>( &str_map_t::find, &m, _1 )
    Этот функтор вернет const_iterator, который указывает на элемент с m или m.end(), если не найден. Здесь вы должны явно указать тип возвращаемого значения str_map_t::const_iterator для boost::bind, чтобы избавиться от неоднозначности.

  2. boost::bind( &str_map_t::const_iterator::operator!=, _1, _2 )
    Этот вернет true, если _1!=_2 и false в противном случае.

Объедините 1 и 2, и мы получим полный код:

#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;
}

Я бы не сказал, что это читаемый код, и я бы порекомендовал написать собственный функтор, чтобы сделать его более читабельным Более читаемая версия может выглядеть следующим образом (без 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) );
5 голосов
/ 24 июня 2010
std::for_each(v.begin(), v.end(), [](std::string& ref) { if m.find(ref) != m.end() /* do something*/ });

Lambdas ftw.

1 голос
/ 24 июня 2010

boost :: lambda - ваша лучшая ставка до C ++ 0x, где они и другие полезные механизмы для функционального программирования станут частью языка, но я рекомендую немного затормозить ваш код, если вы работаете в команде.

Как бы ни был короток и лаконичен этот код, он причиняет много головной боли менее опытным кодировщикам C ++, которые просто не могут понять функторы, предикаты и т. Д. Даже среди тех, кто это делает, он может обеспечить головную боль при попытке отладки код из-за его децентрализующей природы. Мне пришлось пожертвовать всеми этими более функциональными аспектами C ++ в пользу простых циклов for с итераторами только для общего блага команды, с которой я работаю. Возможно, с C ++ 0x проблемы, с которыми другие программисты сталкиваются с функциональным программированием, могли бы быть достаточно смягчены, чтобы их можно было легко понять, и без сложных механизмов шаблонов, которые, к сожалению, многие люди ненавидят.

...