Boost.Lambda: вставить в другую структуру данных - PullRequest
2 голосов
/ 11 ноября 2008

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

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

Так ... что с этим не так?

Ответы [ 5 ]

3 голосов
/ 11 ноября 2008

Ошибка действительно неприятная, но сводится к тому, что она не может определить, какой set :: 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));

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

2 голосов
/ 11 ноября 2008

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

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

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

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

#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 и boost :: lambda :: bind - это два разных зверя. Концептуально они похожи, но они дают результаты разных типов. Только последние могут быть объединены с другими лямбда-операторами.

2 голосов
/ 11 ноября 2008

Я бы использовал цикл for: -D

1 голос
/ 11 ноября 2008

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

for_each(s_vector.begin(), s_vector.end(),
         boost::bind(set<string>::insert, s_set, boost::lambda::_1));
0 голосов
/ 11 ноября 2008

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

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

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

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

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

Спасибо.

...