#include <iostream>
#include <vector>
#include <iterator>
#include <array>
namespace details {
template<
class R,
class iterator_traits,
class iterator_category,
bool is_random_access=std::is_base_of<
std::random_access_iterator_tag,
iterator_category
>::value
>
struct random_access_support {};
template<class R, class iterator_traits, class iterator_category>
struct random_access_support<R, iterator_traits, iterator_category, true> {
R const* self() const { return static_cast<R const*>(this); }
template<class S>
typename iterator_traits::reference operator[](S&&s) const {
return self()->begin()[std::forward<S>(s)];
}
std::size_t size() const { return self()->end()-self()->begin(); }
};
}
template<class It>
struct range:details::random_access_support<
range<It>,
std::iterator_traits<It>,
typename std::iterator_traits<It>::iterator_category
> {
using value_type = typename std::iterator_traits<It>::value_type;
using reference = typename std::iterator_traits<It>::reference;
using iterator = It;
using iterator_category = typename std::iterator_traits<It>::iterator_category;
using pointer = typename std::iterator_traits<It>::pointer;
It begin() const { return b; }
It end() const { return e; }
bool empty() const { return b==e; }
reference front() const { return *b; }
reference back() const { return *std::prev(e); }
range( It s, It f ):b(s),e(f) {}
range()=default;
range(range const&)=default;
range& operator=(range const&)=default;
private:
It b; It e;
};
namespace details {
template<class T>
struct array_view_helper:range<T*> {
using non_const_T = typename std::remove_const<T>::type;
T* data() const { return this->begin(); }
array_view_helper( array_view_helper const& ) = default;
array_view_helper():range<T*>(nullptr, nullptr){}
array_view_helper& operator=(array_view_helper const&)=default;
template<class A>
explicit operator std::vector<non_const_T, A>() const {
return { this->begin(), this->end() };
}
std::vector<non_const_T> as_vector() const {
return std::vector<non_const_T>(*this);
}
template<std::size_t N>
array_view_helper( T(&arr)[N] ):range<T*>(arr+0, arr+N) {}
template<std::size_t N>
array_view_helper( std::array<T,N>&arr ):range<T*>(arr.data(), arr.data()+N) {}
template<class A>
array_view_helper( std::vector<T,A>&vec ):range<T*>(vec.data(), vec.data()+vec.size()) {}
array_view_helper( T*s, T*f ):range<T*>(s,f) {}
};
}
// non-const
template<class T>
struct array_view:details::array_view_helper<T> {
using base = details::array_view_helper<T>;
// using base::base in C++11 compliant compilers:
template<std::size_t N>
array_view( T(&arr)[N] ):base(arr) {}
template<std::size_t N>
array_view( std::array<T,N>&arr ):base(arr) {}
template<class A>
array_view( std::vector<T,A>&vec ):base(vec) {}
array_view( T*s, T*f ):base(s,f) {}
// special methods:
array_view( array_view const& ) = default;
array_view() = default;
array_view& operator=(array_view const&)=default;
};
template<class T>
struct array_view<T const>:details::array_view_helper<const T> {
using base = details::array_view_helper<const T>;
// using base::base in C++11 compliant compilers:
template<std::size_t N>
array_view( T(&arr)[N] ):base(arr) {}
template<std::size_t N>
array_view( std::array<T,N>&arr ):base(arr) {}
template<class A>
array_view( std::vector<T,A>&vec ):base(vec) {}
array_view( T*s, T*f ):base(s,f) {}
// special methods:
array_view( array_view const& ) = default;
array_view() = default;
array_view& operator=(array_view const&)=default;
// const T only constructors:
template<std::size_t N>
array_view( std::array<T,N> const&arr ):base(arr.data(), arr.data()+N) {}
template<std::size_t N>
array_view( std::array<T const,N> const&arr ):base(arr.data(), arr.data()+N) {}
template<class A>
array_view( std::vector<T,A> const&vec ):base(vec.data(), vec.data()+vec.size()) {}
};
void foo( array_view<int> v ) {
for(auto x: v) {
std::cout << x << ",";
}
std::cout << "\n";
v[1] = 3;
for(auto x: v) {
std::cout << x << ",";
}
std::cout << "\n";
}
int main() {
std::vector<int> v = {1,2,3};
foo(v);
}