#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);
}
