The following example allows you to use:
{
int v[5]{1,2,3,4,5};
std::cout << arrayView(v);
int *v2 = new int[5];
std::cout << arrayView(v2, 5);
}
by defining
#include <iostream>
template<class Type>
class ArrayView
{
public:
const Type *const begin, *const end;
};
// creates an ArrayView from a pointer and the number of items
template<class Type>
ArrayView<Type> arrayView(const Type* ptr, size_t items)
{
return { ptr, ptr + items };
}
// creates an ArrayView from a fixed size array
template<class Type, size_t Size>
ArrayView<Type> arrayView(Type (&ptr)[Size])
{
return { ptr, ptr + Size };
}
// outputs an ArrayView
template<class Type>
std::ostream& operator<<(std::ostream& s, ArrayView<Type> v)
{
for (auto it = v.begin; it != v.end; ++it)
s << *it;
return s;
}
int main(int argc, char** argv)
{
double v1[] = { 1, 2, 3, 4 };
double* v2 = new double[5];
for (int i = 0; i < 5; ++i)
v2[i] = i + 10.0;
std::cout << arrayView(v1) << std::endl;
std::cout << arrayView(v2, 5) << std::endl;
return 0;
}
The arrayView
template function initializes an instance of the ArrayView
template class which carries pointer and size (in the form of begin and end pointer).
For fixed size arrays this is not as efficient as it could be. A more efficient solution would be to create a dedicated template which stores the array size within its type:
template<class Type, size_t Size>
class FixedArrayView
{
public:
const Type* const begin;
};
// creates an ArrayView from a fixed size array
template<class Type, size_t Size>
FixedArrayView<Type, Size> fixedArrayView(Type(&ptr)[Size])
{
return { ptr };
}
// outputs a FixedArrayView
template<class Type, size_t Size>
std::ostream& operator<<(std::ostream& s, FixedArrayView<Type, Size> v)
{
for(size_t i = 0; i < Size; ++i)
s << v.begin[i];
return s;
}
This could also be done without the need of an extra template class
template<class Type, size_t Size>
std::ostream& operator<<(std::ostream& s, Type(&arr)[Size])
{
for (size_t i = 0; i < Size; ++i)
s << arr[i];
return s;
}
which allows you to write
{
int v[5]{1,2,3,4,5};
std::cout << v;
}
But the latest template operator<< has a big problem which strikes you if you , for example, try to output some string literal with std::cout << "abc";
However, there is a solution using SFINAE to make this template not handle "const char" (for which there already is an operator<< defined by <iostream>):
template<class Type, size_t Size, typename std::enable_if<!std::is_same<Type, const char>::value>::type* = nullptr>
std::ostream& operator<<(std::ostream& s, Type(&ptr)[Size])
{
for (size_t i = 0; i < Size; ++i)
s << ptr[i];
return s;
}