Here's how I envision a `std::vector` design without the self reference
trap, like (the just sufficient for the OP's example) `my::Vec` below:
-----------------------------------------------------------------------
#include <vector>
#include <string>
#include <functional> // std::(less_or_equal)
#include <iterator> // std::iterator_traits
#include <memory> // std::addressof
#include <type_traits> // std::is_same_v
#include <utility> // std::(enable_if_t, move)
namespace my{
using std::addressof, std::move, std::random_access_iterator_tag;
template< bool condition >
using Enable_if_ = std::enable_if_t<condition>;
template< class A, class B >
constexpr bool is_same_type_ = std::is_same_v<A, B>;
template< class T >
using It_category_ = typename
std::iterator_traits<T>::iterator_category;
template< class Item >
class Vec:
private std::vector<Item>
{
using Base = std::vector<Item>;
public:
using iterator = typename Base::iterator;
using const_iterator = typename Base::const_iterator;
using Index = typename Base::difference_type;
using Base::begin;
using Base::cbegin;
using Base::data;
using Base::end;
using Base::front;
using Base::push_back;
using Base::reserve;
using Base::size;
template<
class Rnd_it,
class = Enable_if_<is_same_type_<
It_category_<Rnd_it>,
random_access_iterator_tag
> >
>
auto insert(
const const_iterator position,
const Rnd_it first,
const Rnd_it last )
-> iterator
{
const Index i_position = position - cbegin();
iterator pos = begin() + i_position;
if( first == last ) {
return pos;
}
const auto p_first = addressof( *first );
constexpr auto less_or_equal = std::less_equal<const Item*>();
if( less_or_equal( data(), p_first ) and
less_or_equal( p_first, data() + size() ) ) {
Vec copies( first, last );
reserve( size() + (last - first) );
for( Item& item: copies ) {
pos = Base::insert( pos, move( item ) );
}
return pos;
}
return Base::insert( position, first, last );
}
template< class Input_it>
auto insert_input(
const const_iterator position,
const Input_it first,
const Input_it last
) -> iterator
{
using Rnd_tag = random_access_iterator_tag;
if constexpr( is_same_type_<It_category_<Input_it>,
Rnd_tag> ) {
return insert( position, first, last );
} else {
return Base::insert( position, first, last );
}
}
using Base::Base;
};
} // namespace my
auto main()
-> int
{
my::Vec<std::string> v
{
"1",
"2",
"3",
};
v.push_back(v.front());
for( int i = 0; i < 2; ++i ) {
v.insert( v.end(), v.begin(), v.begin() + 3 );
}
return v.size();
}
-----------------------------------------------------------------------
> [snip]
Cheers!,
- Alf