erasing_adapter

Antervis
Antervis

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

std::set<T> s;
for (auto it = s.begin(); it != s.end(); ) {
    if (cond(*it)) {
        foo(*it);
        it = s.erase(it);
    } else {
        bar(*it);
        it++;
    }
}

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

std::set<T> s;
for (auto a = erasing_adapter(s); auto& x : a) {
    if (cond(x)) {
        foo(x);
        a.erase_current();
    } else {
        bar(x);
    }
}

где erase_current() будет лишь выставлять флаг, в зависимости от которого итератор адаптера в операции инкремента будет сначала удалять текущий. proof of concept. Note: для некоторых типов структур данных нужно будет сделать специализации, например, такая будет делать O(N^2) мувов для std::vector

0
рейтинг
2 комментария
Nate Reinar Windwood

https://en.cppreference.com/w/cpp/container/set/erase_if

Алсо, по идее, Ranges позволяют это делать через filter и (|=). Не нужно лишних сущностей.

Nate Reinar Windwood
Antervis

Nate Reinar Windwood, filter не умеет работать in_place, а erase_if не умеет делать действия над элементами (если не выносить его в предикат, но это введет среднего читающего в ступор)

Antervis
Другие идеи
Группа создана, чтобы собирать предложения к стандарту C++, организовывать их внутренние обсуждения, помогать готовить их для отправки в комитет и защищать на общих собраниях в рабочей группе по С++ Международной организации по стандартизации (ISO).
Все предложения