Функция std::copy_if() применяется для копирования значений, которые соответствуют некоторому условию, из одного диапазона в другой. Эта функция имеет ряд версий, рассмотрим одну из из них:
iterator std::copy_if(start_source_iterator, end_source_iterator, start_dest_iterator, condition)
Первые два параметра - start_source_iterator и end_source_iterator представляют соответственно итераторы на начало и конец диапазона значений, откуда надо копировать значения. Третий параметр - start_dest_iterator представляет итератор на начало диапазона, в который надо вставить скопированные значения.
Последний параметр - condition представляет условие. В качестве условия выступает функция, которая принимает некоторое значение произвольного типа и возвращает значение типа
bool - true
, если значение соответствует условию, и false
- если не соответствует.
Результатом функции является итератор, который указывает на адрес сразу после последнего скопированного элемента из исходного диапазона.
Рассмотрим применение функции:
#include <iostream> #include <vector> #include <algorithm> // если число четное bool is_even(int n){ return n % 2 == 0;} // если число положительное bool is_positive(int n){ return n > 0;} // для вывода вектора на консоль void print (const std::vector<int>& data) { for(const auto& n: data) { std::cout << n << "\t"; } std::cout << std::endl; } int main() { std::vector<int> numbers { -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}; std::vector<int> even_numbers (numbers.size()); std::vector<int> pos_numbers (numbers.size()); auto end_even_iter = std::copy_if(begin(numbers), end(numbers), begin(even_numbers), is_even); even_numbers.erase(end_even_iter, end(even_numbers)); print(even_numbers); // -4 -2 0 2 4 auto end_pos_iter = std::copy_if(begin(numbers), end(numbers), begin(pos_numbers), is_positive); pos_numbers.erase(end_pos_iter, end(pos_numbers)); print(pos_numbers); // 1 2 3 4 5 }
В данном случае копируем из вектора чисел numbers в два других вектора - even_numbers и pos_numbers. Обратите внимание, что для обоих последних векторов задана длина:
std::vector<int> even_numbers (numbers.size()); std::vector<int> pos_numbers (numbers.size());
Теоретически все элементы вектора numbers могут соответствовать условию, поэтому для обоих векторов устанавливается длина, равная длине вектора numbers.
Условия заданы отдельными функциями - is_even (определяет, является ли число четное) и is_positive (является ли число положительным).
Сначала копируем из вектора numbers в вектор even_numbers все числа, которые являются четными:
auto end_even_iter = std::copy_if(begin(numbers), end(numbers), begin(even_numbers), is_even);
Тут диапазон поиска значений определяется итераторами на начало и конец вектора numbers. Вставляться скопированные элементы будут начиная с начала вектора even_numbers (begin(even_numbers)), а в качестве условия выступает функция is_even.
В реальности выполнение функции будет аналогично следующему:
auto output_iter = begin(even_numbers); for (auto input_iter = begin(numbers); input_iter != end(numbers); ++input_iter) { if (*input_iter % 2 == 0) { *output_iter++ = *input_iter; // устанавливаем значения по итератору назначения } } // возвращаем итератор auto end_even_iter = output_iter;
Таким образом, все четные числа из numbers будут скопированы в even_numbers. Но тут есть проблема - не все элементы исходного вектора numbers могут быть четными, а изначальный размер вектора even_numbers равен размеру numbers. Чтобы оставить в even_numbers только скопированное количество элементов, усекаем вектор even_numbers до позиции последнего скопированного элементам, на который указывает указатель end_even_iter.
even_numbers.erase(end_even_iter, end(even_numbers));
Аналогичным образом получаем положительные числа, только в качестве условия применяется функция is_positive:
auto end_pos_iter = std::copy_if(begin(numbers), end(numbers), begin(pos_numbers), is_positive); pos_numbers.erase(end_pos_iter, end(pos_numbers));
Консольный вывод программы:
-4 -2 0 2 4 1 2 3 4 5