C++98 containers defined two kinds of iterator, ::iterator
s and ::const_iterators
. Generally, like this:
struct vec{
iterator be
STL containers are designed to be used in conjunction with STL algorithms. The generic algorithms currently found in the STL deal with iterators, but your template function transport_first
:
template
void transport_first(Container&& c, std::vector& v){
v.emplace_back(*std::forward(c).begin());
}
consists of container-based code, i.e.: it operates on containers rather than on iterators. We may be able to find such container-based algorithms as part of the STL as of C++20 thanks to concepts.
The "STL-like approach" to a generic transport_first
algorithm would actually be:
template
void transport_first(InIt src, OutIt dst) {
*dst = *src;
}
Following this approach (i.e.: iterators instead of containers), when it comes to generic code, whether to use move_iterator
or not can be simply determined at the "topmost" generic algorithm, since the passed iterators are copied further (i.e.: being passed by value into the "underlying" algorithms).
In addition, unlike the iterator-based transport_first
above, the STL is full of iterator pair-based algorithms (e.g.: std::copy
) to implement ranges. This interface makes overloading those container member functions on rvalues little attractive, because as already stated in this other answer, those overloaded member functions will be called, among others, on unnamed (non-const
) container objects, and unnamed container objects are limited to be used in a single expression, hindering the creation of an iterator pair by calling both begin()
and end()
member functions on the same container object.
What would really make sense for containers, is to have fresh new member functions for returning the corresponding move_iterator
objects:
move_iterator Container::mbegin();
move_iterator Container::mend();
This would be just a shortcut for calling std::make_move_iterator
with the value returned by the member functions returning a iterator
. The member function mbegin()
would be used in the iterator-based transport_first
as:
transport_first(coll.mbegin(), std::back_inserter(vec));
The corresponding function templates std::mbegin()
and std::mend()
would also make sense:
transport_first(std::mbegin(coll), std::back_inserter(vec));