2013-03-11 3 views
1

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

#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; 

    } 
+0

Не должен ли цикл for быть частью 'move_if', а не основной программы? И что вы подразумеваете под 'if (pred)'? – jogojapan

+1

Обратите внимание, что с C++ 11 существует разница между перемещением и копированием элемента. Таким образом, вы не должны использовать слово «move», если хотите скопировать элементы. Перспектива Googling - семантика должна дать довольно много результатов для начала. – inf

ответ

2

Проверьте это, я сделал некоторые изменения на вашем коде:

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, если функциональность как выше код, в противном случае вы действительно должны двигаться Предметы.

+0

Обратите внимание, что 'v2' в main никогда не изменяется с момента передачи копии. –

+0

@JesseGood: Обновлено, спасибо. – deepmax

+1

Функция с именем 'move_if' должна использовать семантику перемещения ... –

1

Там нет перегрузки std::vector::insert, который принимает предикат в качестве второго аргумента, так что эта линия является неправильным:

o.insert(o.begin(),pred); 

Кроме того, предикат должен быть вызван с аргументом,

pred(someArg); 

который в вашем случае будет std::vector<int>::iterator. Кроме того, save_if - это не то же самое, что и move_if. Но что еще более важно, совсем не ясно, чего вы пытаетесь достичь.

3

Попробуйте это ...

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 on cppreference.com; он удаляет элементов из диапазона ввода и копирует их на выход, если предикат не возвращает true.

Обратите внимание, что это STL удалите, поэтому вам нужно удалить стирание после этого, чтобы сжать входной сигнал. Семантика этого решения несколько отличается от кода, который вы опубликовали, но больше похожа на ваше описание того, что вы хотели.

+0

Обратите внимание, что remove_copy_if не перемещается, а копирует его элементы. – inf

+0

Так что код OP. – Useless

+0

@bamboon Я уточнил и улучшил свой ответ; что вы думаете? –

1

В C++ 11, без учета состояния lambdas, такие как [](){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/end, возьмите один объект, на который begin(c) и end(c) были переопределены, чтобы вернуть начало/конец. Если вы работаете над субдиапазоном, вы можете передать в начало/конец диапазон итераторов struct с начальным/конечным назначением соответственно переопределенным.

Смежные вопросы