2008-11-10 6 views
2

J'ai un vector que je veux insérer dans un set. C'est l'un des trois appels différents (les deux autres sont plus complexes, impliquant boost::lambda::if_()), mais résoudre ce cas simple m'aidera à résoudre les autres.Boost.Lambda: Insérer dans une structure de données différente

std::vector<std::string> s_vector; 
std::set<std::string> s_set; 
std::for_each(s_vector.begin(), s_vector.end(), s_set.insert(boost::lambda::_1)); 

Malheureusement, cela ne fonctionne pas avec un message d'erreur de conversion (en essayant de convertir boost::lambda::placeholder1_type-std::string).

Alors ... qu'est-ce qui ne va pas?

Répondre

3

L'erreur est vraiment méchante, mais se résume au fait qu'elle ne peut pas savoir quel set :: insert utiliser, puisqu'il y a trois surcharges.

Vous pouvez travailler autour de l'ambiguïté en donnant une main secourable lier, en spécifiant un pointeur vers la fonction que vous souhaitez utiliser:

typedef std::set<std::string> s_type; 
typedef std::pair<s_type::iterator, bool>(s_type::*insert_fp)(const s_type::value_type&); 
std::for_each(s_vector.begin(), s_vector.end(), boost::bind(static_cast<insert_fp>(&s_type::insert), &s_set, _1)); 

Il est pas joli, mais cela devrait fonctionner.

+0

J'essayais de le faire, mais je ne trouvais pas la bonne combinaison de typedefs et de distributions statiques à utiliser. Cela ressemble à cela fera exactement ce que je veux, bien que je vais probablement utiliser une solution légèrement plus simple similaire à celle fournie par Alastair ci-dessus. C'est l'une des underbellies de boost :: lambda. :( –

1

Je pense qu'une partie du problème est que for_each() attend un foncteur et que vous lui transmettez le résultat d'un appel de fonction. Votre code appelle donc d'abord vector<string>::insert(), puis transmet le résultat de cet appel à for_each(). Je ne suis pas sûr de la syntaxe exacte, mais je pense que vous voulez utiliser bind en combinaison avec lambda ici. par exemple.

for_each(s_vector.begin(), s_vector.end(), 
     boost::bind(set<string>::insert, s_set, boost::lambda::_1)); 
0

Malheureusement, ceci:

std::for_each(s_vector.begin(), s_vector.end(), 
     lambda::bind(&std::set<std::string>::insert, s_set, lambda::_1)); 

ne fonctionne pas. (Notez que j'ai utilisé set :: insert, parce que c'est ce que s_set est.) L'erreur est vraiment désagréable, mais se résume au fait qu'elle ne peut pas savoir quel set :: insert utiliser, puisqu'il y a trois surcharges. Celui que j'essaie d'utiliser est l'ensemble qui retournera pair :: iterator, bool> (l'insertion de valeur). De toute évidence, cela ne fonctionne pas.

J'ai remarqué que vous utilisiez boost :: bind, pas boost :: lambda :: bind - était-ce intentionnel? (Ils semblent fonctionner un peu différemment.)

Je pense que vous avez raison d'attendre un foncteur plutôt qu'un résultat d'appel de fonction; Je suis sûr que cela peut être transformé en un foncteur, mais mon cerveau ne voit pas la réponse en ce moment.

Merci.

+0

Je ne connaissais pas boost :: lambda :: bind. Je n'ai pas beaucoup utilisé boost :: lambda. – Ferruccio

2

J'utiliser une boucle for :-D

+0

En effet, beaucoup le feraient, mais for_each rend plus facile la modification de la structure de données plus tard –

+0

meilleure réponse :) upvote pour cela –

2

Pour copier uniquement le vecteur dans l'ensemble, vous pouvez utiliser std :: copie et un itérateur d'insertion. Quelque chose comme:

std::copy(s_vector.begin(), s_vector.end(), std::inserter(s_set, s_set.end())); 

Bien sûr, cela ne veut pas utiliser boost :: lambda du tout, donc il ne probablement pas vous aider à faire généraliser ce que vous voulez. Il serait préférable d'en savoir plus sur ce que vous essayez de faire ici. Je vais supposer, d'après votre mention de lambda :: _ if, que votre lambda va faire une sorte de filtrage du vecteur d'entrée avant de l'insérer dans l'ensemble.

L'exemple suivant (complet, testé) montre comment copier uniquement les chaînes qui sont < = 4 caractères du vecteur dans l'ensemble:

#include <boost/assign/list_of.hpp> 
#include <boost/lambda/lambda.hpp> 
#include <boost/lambda/bind.hpp> 
#include <boost/test/minimal.hpp> 

#include <set> 
#include <vector> 
#include <algorithm> 

using namespace std; 
using namespace boost::lambda; 
using namespace boost::assign; 

int test_main(int argc, char* argv[]) 
{ 
    vector<string> s_vector = list_of("red")("orange")("yellow")("blue")("indigo")("violet"); 
    set<string> s_set; 

    // Copy only strings length<=4 into set: 

    std::remove_copy_if(s_vector.begin(), s_vector.end(), std::inserter(s_set, s_set.end()), 
         bind(&string::length, _1) > 4u); 

    BOOST_CHECK(s_set.size() == 2); 
    BOOST_CHECK(s_set.count("red")); 
    BOOST_CHECK(s_set.count("blue")); 

    return 0; 
} 

Espérons que cela vous donne quelque chose à aller? Je voudrais aussi réitérer le point ci-dessus que boost :: bind et boost :: lambda :: bind sont deux bêtes différentes. Conceptuellement, ils sont similaires, mais ils produisent des sorties de différents types. Seul ce dernier peut être combiné avec d'autres opérateurs lambda.

+0

Comme vous l'avez supposé, ma solution actuelle est de faire un filtrage de correspondance positive lors de l'insertion; Je fais aussi face à des objets qui sont significativement plus lourds que la ficelle - mais je pense que cela me met sur la bonne voie. –

Questions connexes