2008-11-10 1 views
2

У меня есть vector, который я хочу вставить в set. Это один из трех разных вызовов (два других сложнее, включая boost::lambda::if_()), но решение этого простого случая поможет мне решить остальные.Boost.Lambda: Вставить в другую структуру данных

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

К сожалению, это не удается с сообщением об ошибке преобразования (пытается преобразовать boost::lambda::placeholder1_type в std::string).

Итак ... что в этом плохого?

ответ

3

Ошибка действительно неприятная, но сводится к тому, что она не может определить, какой набор :: insert использовать, поскольку есть три перегрузки.

Вы можете обойти двусмысленности, давая связать полезную руку, указав указатель на функцию вы хотите использовать:

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

Это не красиво, но он должен работать.

+0

Я пытался это сделать, но не нашел правильную комбинацию typedefs и статических применений. Похоже, что это будет делать именно то, что я хочу, хотя я, вероятно, воспользуюсь немного более простым решением, аналогичным тому, что было предложено Alastair выше. Это одна из подстилок boost :: lambda. :( – 2008-11-11 06:43:03

1

Я думаю, что часть проблемы заключается в том, что for_each() ожидает функтора, и вы передаете ему результат вызова функции. Таким образом, ваш код сначала вызовет vector<string>::insert(), а затем передаст результат этого вызова for_each(). Я не уверен в точном синтаксисе, но я думаю, что вы хотите использовать bind в сочетании с лямбдой здесь. например

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

К сожалению, это:

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

не работает. (Обратите внимание, что я использовал set :: insert, потому что это то, что s_set.) Ошибка действительно противная, но сводится к тому, что она не может определить, какой набор :: insert использовать, поскольку есть три перегрузки. Тот, который я пытаюсь использовать, - это набор, который будет возвращать пару :: iterator, bool> (значение insert). Очевидно, что это не работает.

Я заметил, что вы использовали boost :: bind, а не boost :: lambda :: bind - это было намеренно? (Кажется, они работают по-другому.)

Я думаю, что вы правы в ожидании функтора, а не в результате вызова функции; Я уверен, что это можно превратить в функтора, но мой мозг не видит ответа прямо сейчас.

Спасибо.

+0

Я не знал о boost :: lambda :: bind. Я не использовал boost :: lambda много. – Ferruccio 2008-11-11 00:39:12

2

Я хотел бы использовать для цикла :-D

+0

Действительно, многие будут. Однако for_each упростит изменение структуры данных позже. – 2008-11-11 03:16:29

+0

лучший ответ :) upvote для этого – 2008-11-11 08:50:14

2

Чтобы просто скопировать вектор в набор, вы можете использовать зЬй :: копию и вставки итератор. Что-то вроде:

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

Конечно это не использовать повышение :: лямбда вообще, так что это, вероятно, не поможет вам обобщить это делать то, что вы хотите. Было бы лучше узнать больше о том, что вы пытаетесь сделать здесь. Я собираюсь предположить, основываясь на вашем упоминании лямбда :: _, если ваша лямбда собирается сделать какую-то фильтрацию входного вектора перед вставкой в ​​набор.

Следующий (полный, испытано) пример показывает, как скопировать только строки, которые < = 4 символов из вектора в комплект:

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

Надеется, что это дает вам то, чтобы идти дальше?

Также позвольте мне повторить вышеописанную точку: boost :: bind and boost :: lambda :: bind - это два разных зверя. Концептуально они похожи, но они производят результаты разных типов. Только последние могут быть объединены с другими лямбдами.