Как передать двумерный массив в функцию без динамического выделения памяти?
Для неизменяемых данных я придумал.#include <iostream>

template <class T>
struct Array
{
    const size_t size;
    const T* const data;

    const T* begin() const { return data; }
    const T* end() const { return data + size; }

    constexpr Array(const std::initializer_list<T>& x)
        : size(x.size()), data(x.begin()) {}
};

using Row = Array<int>;
using Matrix = Array<Row>;

Matrix mtx = {
  {1, 2, 3 },
  { 10, 20, 30, 40, 50 },
  {},
  { 100 }
};

int main()
{
    for (auto& u : mtx) {
        for (auto& v : u) {
            std::cout << v << ' ';
        }
        std::cout << std::endl;
    }
    return 0;
}
Для изменяемых данных пока вышло только так.#include <iostream>

// Изменяемый вариант
template <class T>
struct Array2
{
    const size_t size;
    T* const data;

    T* begin() { return data; }
    T* end() { return data + size; }
    const T* begin() const { return data; }
    const T* end() const { return data + size; }
    T& operator[](int i) { return data[i]; }

    template <size_t N>
    constexpr Array2(T (&x)[N])
        : size(N), data(x) {}
};

using Row2 = Array2<int>;
using Matrix2 = Array2<Row2>;

int main()
{
    int i;
    std::cin >> i;

    int row1[] = { 1, i, 3 };
    int row2[] = { 10, 2*i, 30, 3*i, 50 };
    int row3[] = { 13 };
    int row4[] = { 100 };

    Row2 mtx[] = { row1, row2, row3, row4 };

    mtx[1][4] = i * 6;

    for (auto& u : mtx) {
        for (auto& v : u) {
            std::cout << v << ' ';
        }
        std::cout << std::endl;
    }
    return 0;
}
Можно ли как-то возложить на компилятор эту работу?int arr[] = {1, 2, 3};
size_t size = sizeof(arr)/sizeof(arr[0]);  // size == 3
Но как вы это прикрутите к вашей схеме не знаю. 
Возможно есть смысл определить ваши массивы как константы по одному и использовать эти константы для инициализации test и вычисления sizeof().