cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
90 stars 0 forks source link

Добавить в стандартные контейнеры перегрузки begin(), end() с rvalue ref-qualifiers, возвращающие move_iterator<iterator> #406

Open apolukhin opened 3 years ago

apolukhin commented 3 years ago

Перенос предложения: голоса +4, -1 Автор идеи: Andrey Davydov

В настоящее время нет удобного способа помувать данные из временного контейнера, для этого используются костыли std::make_move_iterator и алгоритм std::move вместо std::copy. Однако, если придерживаться идеи, что контейнер владеет своими элементами, что кажется очень естественным в идеологии STL, то получается, что элементы временного контейнера тоже временные, а значит, их можно мувать без лишних телодвижений.

Рассмотрим такой код:

struct OnlyMovable {
    OnlyMovable(OnlyMovable&&) = default;
    OnlyMovable(OnlyMovable const &) = delete;
};

OnlyMovable modify(OnlyMovable o)
{
    // do something with `o`
    // ...

    return o;
}

std::vector<OnlyMovable> produce();

// я предполагаю, что реализация std::transform от range в С++20
// должна работать примерно так
template<typename Range, typename OutIt, typename Functor>
void transform(Range && range, OutIt out, Functor f)
{
    using std::begin, std::end, std::forward;
    std::transform(begin(forward<Range>(range)),
                   end  (forward<Range>(range)),
                   out, f);
}

void test()
{
    std::vector<OnlyMovable> out;
    transform(produce(), std::back_inserter(out), modify);
}

Сейчас он не скомпилируется, так как у нас не получится передать элемент вектора в функцию modify по значению. Это можно поправить, если заменить return type функции produce() на что-то подобное:

template<typename T>
struct myvector {
    using iterator = T*;
    using const_iterator = T const *;

    iterator                        begin()        & ;
    iterator                        end()          & ;
    const_iterator                  begin()  const & ;
    const_iterator                  end()    const & ;
    std::move_iterator<iterator>    begin()        &&;
    std::move_iterator<iterator>    end()          &&;
};

и, соответственно, добавить перегрузки функций std::begin, std::end от rvalue-ranges.