Повысить оценку размера лямбда-коллекции

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

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);
Другие вопросы по тегам