Стандартные алгоритмы обычно не работают с несколькими выходными адресатами, поэтому здесь сложно найти подходящее решение, если вы хотите абстрагировать контейнеры назначения с помощью итераторов вывода.Что может быть ближе всего - это std::copy_if
.Это может выглядеть следующим образом:
// Help predicate creation:
auto pred = [](int target){ return [target](const Foo& f){ return f.target == target; }; };
std::copy_if(elements.begin(), elements.end(), std::back_inserter(As), pred(Foo::A));
std::copy_if(elements.begin(), elements.end(), std::back_inserter(Bs), pred(Foo::B));
std::copy_if(elements.begin(), elements.end(), std::back_inserter(Cs), pred(Foo::C));
std::copy_if(elements.begin(), elements.end(), std::back_inserter(others),
[](const Foo& f){ return false; /* TODO */ });
elements.clear();
Если копирование обходится дороже, чем создание ходов, вы должны передать алгоритму std::make_move_iterator(elements.begin())
и то же самое для elements.end()
.Проблема здесь в том, что это не масштабируется.std::copy_if
линейно пересекает входной диапазон, и вышеописанное должно сделать это четыре раза.Один обход может быть получен, например, следующим образом.
auto doTheWork = [&As, &Bs, &Cs, &others](const Foo& foo) {
if (foo.target == Foo::A)
As.push_back(foo);
else if (foo.target == Foo::B)
Bs.push_back(foo);
else if (foo.target == Foo::C)
Cs.push_back(foo);
else
others.push_back(foo);
};
std::for_each(elements.begin(), elements.end(), doTheWork);
В этом сценарии мы по крайней мере использовали стандартный алгоритм, но сместили логику в довольно некрасивую лямбду.Обратите внимание, что лямбда, указанная выше, всегда будет копировать свои аргументы, для корректной работы с std::move_iterator
s необходимо несколько настроек. Иногда старый добрый диапазон, основанный на цикле, является наиболее читаемым решением.