У меня проблема с передачей предиката с помощью лямбды, я пытаюсь переместить элемент, который соответствует предикату, в начало второго контейнера, но, похоже, он не работает, так что не так, пожалуйста?
#include <iostream>
#include <vector>
#include <list>
#include <iterator>
#include <utility>
#include <algorithm>using namespace std;
template <typename iterator, typename Container, typename T>
void move_if(iterator b, iterator e, Container o, T pred)
{
if(pred)
{
o.insert(o.begin(),pred);
}
}int main()
{
vector<int>v{1,2,3,4,5,6,7,8,9,10};
vector<int>v2;
for (auto i=v.begin(); i !=v.end(); ++i)
save_if(v.begin(), v.end(), v2, []( vector<int>::iterator i){return (*i>5);});
return 0;
}
Проверьте это, я сделал некоторые изменения в вашем коде:
template <typename iterator, typename Container, typename T>
void move_if(iterator a, iterator b, Container &o, T pred)
{
for (auto i = a; i != b; i++)
{
if (pred(*i))
o.insert(o.begin(), *i);
}
}
int main()
{
vector<int>v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
vector<int>v2;
move_if(v.begin(), v.end(), v2, [](int i) { return !(i > 5); });
}
Примечание: в комментариях рекомендуется переименовать move_if
в copy_if
, если функциональность такая же, как в приведенном выше коде, в противном случае вы должны действительно перемещать элементы
Попробуй это…
int main()
{
std::vector<int> v{1,2,3,4,5,6,7,8,9,10};
std::vector<int> v2;
std::vector<int>::const_iterator
it = std::remove_copy_if(v.begin(), v.end(),
std::back_inserter(v2),
[](int const& i){return i <= 5;});
v.erase(it, v.end);
return 0;
}
Вы можете прочитать больше о remove_copy_if
на cppreference.com; Это удаляет элементы из входного диапазона и копируют их в выходные данные, если предикат не возвращает true.
Обратите внимание, что это STL Удалить, так что вам нужно вызвать стирание потом, чтобы уменьшить ввод. Семантика этого решения немного отличается от кода, который вы разместили, но больше похожа на ваше описание того, что вы хотели.
Там нет перегрузки станд :: вектор :: вставка который принимает предикат в качестве второго аргумента, поэтому эта строка неверна:
o.insert(o.begin(),pred);
Кроме того, предикат должен быть вызван с аргументом,
pred(someArg);
который в вашем случае будет std::vector<int>::iterator
, Также, save_if
это не то же самое, что move_if
, Но что еще более важно, не совсем понятно, чего вы пытаетесь достичь.
В C ++ 11 лямбды без сохранения состояния, такие как [](){return true}
которые ничего не фиксируют, могут быть неявно преобразованы в указатели на функции. Когда вы делаете if(pred)
вы конвертируете лямбду без сохранения состояния в указатель на функцию, проверяя, является ли этот указатель ненулевым (ненулевым). Это не то, что вы хотите сделать.
Вот реализация, которая move
вещи между b
а также e
тот pred(x)
говорит, должен быть перемещен:
template <typename iterator, typename Container, typename T>
void move_if(iterator b, iterator e, Container o, T pred)
{
for( auto i = b; i != e;++i) {
if(pred) {
o.insert(o.end(),std::move(*i));
}
}
}
Обратите внимание, что я вставил в o.end()
, поскольку Container
Вы хотите, вероятно, vector
и вставляя в end()
из vector
намного быстрее
В действительности, вы, вероятно, хотите взять итератор вывода (и по умолчанию использовать std::back_inserter
из Container
) и выведите свои данные на это. Так же, remove_move_if
было бы лучшим способом удалить, перетасовывая элементы вниз по b
—e
диапазон и возвращая iterator
,
Наконец, алгоритмы на основе ранжирования заслуживают написания. Вместо того, чтобы брать пару итератор начала / конца, возьмите единственный объект, на котором begin(c)
а также end(c)
были переопределены, чтобы вернуться начало / конец. Если вы работаете с поддиапазоном, вы можете передать начальный / конечный диапазон итераторов struct
начало / конец соответственно переопределено.