Ускорение проблемы с библиотекой Phoenix или Lambda: удаление элементов из std :: vector - PullRequest
4 голосов
/ 18 октября 2008

Недавно я столкнулся с проблемой, которую я думал, что boost :: lambda или boost :: phoenix может помочь решить проблему, но я не смог правильно понять синтаксис и поэтому сделал это по-другому. Я хотел удалить все элементы в «строках», которые были меньше определенной длины, а не в другом контейнере.

Это моя первая попытка:

std::vector<std::string> strings = getstrings();
std::set<std::string> others = getothers();
strings.erase(std::remove_if(strings.begin(), strings.end(), (_1.length() < 24 &&  others.find(_1) == others.end())), strings.end());

Как в итоге я это сделал:

struct Discard
{
    bool operator()(std::set<std::string> &cont, const std::string &s)
    {
        return cont.find(s) == cont.end() && s.length() < 24;
    }
};

lines.erase(std::remove_if( lines.begin(), lines.end(), boost::bind<bool>(Discard(), old_samples, _1)), lines.end());

Ответы [ 2 ]

3 голосов
/ 18 октября 2008

Вам нужно boost :: labmda :: bind для вызова функции lambda-ify, например, длина <24 становится равной: </p>

bind(&string::length, _1) < 24

EDIT

См. Сообщение "Head Geek" о том, почему set :: find является хитрым. Он получил это, чтобы решить правильную перегрузку set :: find (поэтому я скопировал эту часть), но он пропустил существенное повышение :: ref () - поэтому сравнение с end () всегда не удавалось (контейнер копировался) .

int main()
{
  vector<string> strings = getstrings();
  set<string> others = getothers();
  set<string>::const_iterator (set<string>::*findFn)(const std::string&) const = &set<string>::find;
  strings.erase(
    remove_if(strings.begin(), strings.end(),
        bind(&string::length, _1) < 24 &&
        bind(findFn, boost::ref(others), _1) == others.end()
      ), strings.end());
  copy(strings.begin(), strings.end(), ostream_iterator<string>(cout, ", "));
  return 0;
}
2 голосов
/ 18 октября 2008

Основная проблема, кроме вызовов bind (Адам Митц был прав в этой части), заключается в том, что std::set<std::string>::find - перегруженная функция, поэтому вы не можете указать ее непосредственно в вызове bind. Вам нужно указать компилятору какой find использовать, например, так:

using namespace boost::lambda;
typedef std::vector<std::string> T1;
typedef std::set<std::string> T2;

T1 strings = getstrings();
T2 others = getothers();

T2::const_iterator (T2::*findFn)(const std::string&) const=&T2::find;
T2::const_iterator othersEnd=others.end();

strings.erase(std::remove_if(strings.begin(), strings.end(),
    (bind(&std::string::length, _1) < 24
        && bind(findFn, boost::ref(others), _1) == othersEnd)),
    strings.end());

Это компилируется, но не работает должным образом, по причинам, которые я еще не выяснил ... функция find никогда не возвращает others.end(), поэтому она никогда ничего не удаляет. Все еще работаю над этой частью.

EDIT: исправление, функция find равна , возвращая others.end(), но сравнение не распознает ее. Я не знаю почему.

ПОСЛЕДНЕЕ РЕДАКТИРОВАНИЕ: Благодаря комментарию Адама, я вижу, что идет не так, и исправил проблему. Теперь он работает как задумано.

(Посмотрите историю изменений, если хотите увидеть мою полную тестовую программу.)

...