повысить оценку размера лямбда-коллекции - PullRequest
3 голосов
/ 23 марта 2009

У меня есть функция вида:

void DoSomething(const boost::function<bool ()>& condition, other stuff);

Эта функция выполняет некоторую работу и возвращает только когда условие выполнено. Условие было выражено как аргумент функтора, потому что я хочу предоставить разные условия на разных сайтах вызовов.

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

Один случай, который меня озадачил на данный момент: у меня есть коллекция std::vector под названием data; условие, за которым я следую, - это когда size() этой коллекции достигает определенного порога. По сути, я хочу, чтобы мой функтор condition возвращал true, когда data.size() >= threshold, и false в противном случае. Но мне было трудно выразить это в лямбда-синтаксисе.

Лучшее, что я смог до сих пор придумать (который, по крайней мере, компилируется, хотя и не работает), это:

boost::function<bool (size_t)> ge = boost::bind(std::greater_equal<size_t>(),
                                                _1, threshold);
boost::function<size_t ()> size = boost::bind(&std::vector<std::string>::size,
                                              data);
DoSomething(boost::lambda::bind(ge, boost::lambda::bind(size)), other stuff);

При входе в DoSomething размер равен 0 - и хотя размер увеличивается в ходе выполнения, вызовы condition() всегда, кажется, получают размер 0. Отслеживание этого (что является немного сложнее из внутренних элементов Boost), хотя он, кажется, вызывает greater_equal каждый раз, когда condition() оценивается, он, кажется, не вызывает size().

Так что фундаментального, что я полностью испортил? Есть ли более простой способ выразить подобные вещи (при этом сохраняя код как можно более встроенным)?

В идеале я бы хотел, чтобы он был как можно ближе к беглости кода, эквивалентного C #:

DoSomething(delegate() { return data.size() >= threshold; }, other stuff);
DoSomething(() => (data.size() >= threshold), other stuff);

1 Ответ

5 голосов
/ 23 марта 2009

Проблема в том, что лямбда-функция хранит копию вектора data, а не ссылку. Таким образом, size() вызывается для копии, а не для исходного объекта, который вы изменяете. Это можно решить, обернув data с boost::ref, в котором вместо этого хранится ссылка:

boost::function<size_t ()> size = boost::bind(&std::vector<std::string>::size,
                                              boost::ref(data));

Вы также можете использовать обычный >= оператор вместо std::greater_equal<> в определении вашей лямбда-функции и объединить все это вместе:

boost::function<bool ()> cond =
    (boost::bind(&std::vector<std::string>::size, boost::ref(data))
        >= threshold);

DoSomething(cond, other stuff);
...