#include <iostream>
#include <algorithm>

template<typename T, size_t L, size_t H>
class Array
{
public:
    static_assert(H >= L);
    static const size_t Low = L;
    static const size_t High = H;
    static const size_t Length = (H - L + 1);

    // stuff ...

    template<size_t Lb, size_t Hb>
    operator Array<T, Lb, Hb>() const
    {
        static_assert(Length == Array<T, Lb, Hb>::Length);
        Array<T, Lb, Hb> converted;
        std::copy_n(actualArray, Length, converted.actualArray);
        return converted;
    }

    // just to show that you don't need an offset member...

    T& operator[](size_t idx)
    {
        return actualArray[idx - L];
    }

    T operator[](size_t idx) const
    {
        return actualArray[idx - L];
    }

    template<typename, size_t, size_t>
    friend class Array;
    
private:
    T actualArray[Length];
};

template<typename T, size_t L, size_t H>
void printArray(const Array<T, L, H> &arr)
{
    for (size_t idx = arr.Low; idx <= arr.High; ++idx)
        std::cout << arr[idx] << std::endl;
}

int main()
{
    Array<int, 0, 2> arr1;
    arr1[0] = 1;
    arr1[1] = 2;
    arr1[2] = 3;
    printArray(arr1);

    std::cout << std::endl;

    Array<int, 5, 7> arr2;
    arr2 = arr1;
    printArray(arr2);

	return 0;
}