Повысить оценку размера лямбда-коллекции
У меня есть функция вида:
void DoSomething(const boost::function<bool ()>& condition, other stuff);
Эта функция выполняет некоторую работу и возвращает только когда условие выполнено. Условие было выражено как аргумент функтора, потому что я хочу предоставить разные условия на разных сайтах вызовов.
Теперь это довольно просто использовать напрямую, но это требует объявления множества маленьких одноразовых функций или объектов-функторов, которых я бы хотел избежать, если это возможно. Я искал в лямбда-библиотеке Boost возможные способы покончить с этим, но я думаю, что упускаю что-то фундаментальное; Я просто не могу заставить его делать то, что я хочу.
Один случай, который поставил меня в тупик на данный момент: у меня есть std::vector
коллекция называется data
; условие, что я после того, как size()
этой коллекции достигает определенного порога. По сути, тогда я хочу, чтобы мой condition
функтор, чтобы вернуть истину, когда data.size() >= threshold
и ложь в противном случае. Но у меня были проблемы с выражением этого в синтаксисе лямбды.
Лучшее, что я смог придумать до сих пор (который, по крайней мере, компилируется, хотя и не работает), это:
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 ответ
Проблема в том, что лямбда-функция хранит копию 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);