Отфильтрованные диапазоны, лямбды и is_sorted

Это урезанная версия проблемы с фильтрованными итераторами (поэтому нет смысла просить меня переписать ее по-другому, чтобы избежать фильтров). Как ни странно, только в реальном коде is_sorted Кажется, проблема, другие виды использования работают нормально.

#include <vector>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/algorithm_ext/is_sorted.hpp>

int main(int argc, const char* argv[])
{
using namespace boost::adaptors;
std::vector<int> all = {1,2,3,4,5,6,7,8,9};
auto some = all | filtered([] (int i) { return i % 2; });
return boost::is_sorted(some);
}

Это не удается скомпилировать как с Clang ++ 3.5, так и с G ++ 4.9 (в Mac OS X, в актуальном состоянии):

$ clang++-mp-3.5 -std=c++11 -isystem /opt/local/include/ foo.cc
In file included from foo.cc:3:
In file included from /opt/local/include/boost/range/algorithm_ext/is_sorted.hpp:18:
/opt/local/include/boost/detail/is_sorted.hpp:25:28: error: object of type
'boost::filter_iterator<(lambda at foo.cc:9:30), std::__1::__wrap_iter<int
*> >' cannot be assigned because its copy assignment operator is
implicitly deleted
for (; it != last; first = it, ++it)
^
...

/opt/local/include/boost/iterator/filter_iterator.hpp:106:17: note: copy
assignment operator of 'filter_iterator<(lambda at foo.cc:9:30),
std::__1::__wrap_iter<int *> >' is implicitly deleted because field
'm_predicate' has a deleted copy assignment operator
Predicate m_predicate;
^
foo.cc:9:30: note: lambda expression begins here
auto some = all | filtered([] (int i) { return i % 2; });
^

Я знаю, как хранить свою лямбду в std::function исправляет, но я хочу избежать оплаты
его цена. Используя пользовательскую обертку вокруг std::is_sorted не решает проблему. Эта проблема, кажется, связана с другими (например, итератор повышения трансформации и лямбда с ++ 11),
но это не так — по крайней мере, их лечение здесь не применимо.

Спасибо!

2

Решение

внутри is_sorted итератор, используемый для итерации последовательности, копируется, чтобы его можно было использовать для сравнения смежных элементов. Это означает, что предикат filtered (т. е. ваша лямбда) также должна быть скопирована, даже если она фактически не используется для увеличения конечного итератора. Другие алгоритмы, которые копируют итератор, будут иметь такую ​​же проблему, например, adjacent_find,

Разница между алгоритмами, которые копируют свои итераторы, и теми, которые этого не делают, состоит в том, что первые называются «многоходовыми» алгоритмами и требуют, чтобы их тип итератора удовлетворял ForwardIterator, в то время как последние являются однопроходными и требуют только InputIterator,

Решение состоит в том, чтобы дать вашему локальному лямбда-файлу время жизни и передать его reference_wrapper:

auto odd = [] (int i) { return i % 2; };
auto some = all | filtered(std::ref(odd));

Альтернативой является Приведите лямбду к указателю на функцию, используя +:

auto some = all | filtered(+[] (int i) { return i % 2; });

Это работает только с лямбдами без захвата, и потенциально неясно.

7

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector