vector2 is a fundamentally different type. If, however, you just want to view the inside of vector1 in a const manner, I have a solution for you.
I'd start with something like, but not exactly, gsl::span.
template<class T>
struct span {
private:
T* b = 0;
T* e = 0;
public:
T* begin() const { return b; }
T* end() const { return e; }
T* data() const { return begin(); }
template<class U>
using compatible = std::enable_if_t< std::is_convertible< U*, T* >{} && sizeof(T)==sizeof(U), bool >;
template<class U,
compatible<U> =true
>
span( U* s, U* f ): b(s), e(f) {}
template<class U,
std::enable_if_t< std::is_convertible< U*, T* >{} && sizeof(T)==sizeof(U), bool > =true
>
span( U* s, std::size_t length ): span( s, s+length ) {}
// pointer semantics:
span()=default;
span(span const&)=default;
span& operator=(span const&)=default;
~span()=default;
std::size_t size() const{ return end()-begin(); }
bool empty() const{ return end()==begin(); }
T& front() const { return *begin(); }
T& back() const { return *(end()-1); }
// sub spans:
span without_front( std::size_t n=1 ) const {
n = (std::min)(n, size());
return {begin()+n, end()};
}
span without_back( std::size_t n=1 ) const {
n = (std::min)(n, size());
return {begin(), end()-n};
}
span only_front( std::size_t n=1 ) const {
n = (std::min)(n, size());
return {begin(), begin()+n};
}
span only_back( std::size_t n=1 ) const {
n = (std::min)(n, size());
return {end()-n, end()};
}
span sub( std::size_t start, std::size_t length ) const {
return without_front(start).only_front(length);
}
T& operator[](std::size_t I)const{ return begin()[I]; }
T& at(std::size_t I)const{
if (I>=size()) throw std::out_of_range{"index"};
return begin()[I];
}
std::vector<std::decay_t<T>> as_vector()const& {
return {begin(), end()};
}
std::vector<std::decay_t<T>> as_vector()&& {
return {std::make_move_iterator(begin()), std::make_move_iterator(end())};
}
template<class C,
compatible< std::decay_t< decltype( *std::declval<C&>().data() ) > > =true,
std::enable_if_t< !std::is_same<span, std::decay_t<C>>{}, bool > =true
>
span( C&& c ): span(c.data(), c.size()) {}
};
If you do not intend to change the length of a vector in a context, a span is the right answer.
Live example with some tests.
Function in this case should take span< MyObj const*const >, stating it just wants to look at a buffer of MyObj consts. You can store a span of this type if you want to, or let implicit conversion work:
std::vector<MyObj*> ArrayOfPtr;
span<MyObj const*const> SpanOfPtrToConstObj;
int main()
{
//I'd like to give ArrayOfPtr to another obj/function but not give it the right to modify the objects in it.
SpanOfPtrToConstObj = ArrayOfPtr;
Function(SpanOfPtrToConstObj)
}
Function cannot modify the length of the vector or the pointers within it or what the pointers point to.