В C++ отсутствует простой класс «вид в непрерывный блок памяти». Вот один:
template<class T>
struct ro_array_view {
T const* b_ = nullptr;
T const* e_ = nullptr;
size_t size() const { return end()-begin(); }
T const* begin() const { return b_; }
T const* end() const { return e_; }
T const& operator[](size_t i)const{ return begin()[i]; }
bool empty()const{return begin()==end();}
T const& front() const { return *begin(); }
T const& back() const { return *std::prev(end()); }
// annoying numbers of constructors:
struct from_container_tag {};
template<class O>
ro_array_view(from_container_tag, O&& o):
ro_array_view(o.data(), o.size()) {}
template<class...A>
ro_array_view(std::vector<T,A...> const& o)
:ro_array_view(from_container_tag{},o) {}
ro_array_view(std::initializer_list<T> const& il)
:ro_array_view(il.begin(), il.size()) {}
template<size_t N>
ro_array_view(std::array<T, N> const& o)
:ro_array_view(from_container_tag{},o) {}
template<size_t N>
ro_array_view(std::array<T const, N> const& o)
:ro_array_view(from_container_tag{},o) {}
template<size_t N>
ro_array_view(T const(&arr)[N])
:array_view(arr, N) {}
// penultimate constructor of most paths:
ro_array_view(T const* arr, size_t N)
:ro_array_view(arr, arr+N) {}
// terminal constructor:
ro_array_view(T const* b, T const* e)
:b_(b),e_(e) {}
};
теперь просто взять ro_array_view<int>
и преобразует входящий аргумент в пару указателей, и выставить только для чтения контейнера-подобный интерфейс к нему.
Это кажется излишним на первый взгляд, но вы обнаружите, что это очень распространенная функция для использования. Огромный кусок функций, которые принимают std::vector<T> const&
, должен принимать значение ro_array_view<T>
.
не- ro_array_view
немного отличается (его методы все в основном const
до сих пор, но он хранит T*
не T const*
. Я бы назвал это rw_array_view
, а затем сделать array_view
using
псевдоним, который условно использует ro_array_view
или rw_array_view
. Добавить в преобразующий т е р от rw_array_view
к ro_array_view
, чтобы закончить проект.
у меня есть два разных типа, вместо одного, потому что rw_array_view
и ro_array_view
имеют различные конструкторы из некоторого контейнера. rw_array_view<T>
может быть изготовлен из vector<T,A...>&
, а ro_array_view<T>
- vector<T, A...>const&
. std::array
немного хуже, потому что const T
является допустимым типом в std::array
. И ro_array_view
используется в большинстве случаев, причем rw_array_view
полезен для случаев, когда мы хотим изменить содержимое без изменения контейнера.
Вектор не initializer_list. Тем не менее, оба являются диапазонами, вы можете использовать begin/end или для циклов на обоих и совместно использовать код таким образом. –
Да, я знаю, что вектор не является списком инициализаторов, но угрюмым он является конвертируемым? – Adrian
нет это нет (можно сменить). И этого не должно быть. 'initializer_list' был создан так, чтобы контейнеры, такие как вектор, создавались из них, а не наоборот. – bolov