#include <iostream>
using namespace std;

template<size_t Index, size_t N>
constexpr bool checkArrayBounds()
{
    return Index < N || (throw "Index out of bounds", false);
}

template<size_t Index, typename T, size_t N>
constexpr T array_at(T(&array)[N]) // `array` is a reference to `T[N]`
{
    return checkArrayBounds<Index, N>(), *(array+Index); // Comma magic *-*
}

int main()
{
    constexpr int x[] { 1, 2, 3 };

    static_assert(array_at<0>(x) == 1, "Error");
    static_assert(array_at<1>(x) == 2, "Error");
    static_assert(array_at<2>(x) == 3, "Error");

    cout << array_at<0>(x) << endl;
    cout << array_at<1>(x) << endl;
    cout << array_at<2>(x) << endl;

    return 0;
}