#include <boost/type_traits/is_array.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/static_assert.hpp>
#include <iostream>


using namespace boost;

struct empty {};

template <class A>
struct dimension0
{
    static A a;
    enum {e = sizeof(a[0])};
    typedef char (&type)[sizeof(A)/e];
};

template <class T>
struct eval0
{
    typedef typename T not_array;
};

template <>
struct eval0<void>
{};

template <
    std::size_t d
  , class A
>
struct legal_array_counter;

template <
    std::size_t d
  , class A
>
struct array_counter
{
    enum { legal = is_array<A>::value };

    BOOST_MPL_ASSERT((is_array<A>));
    
    typedef typename mpl::eval_if_c<
        !legal
      , mpl::identity<void>
      , legal_array_counter<d,A>
    >::type type;
};

template <
    std::size_t d
  , class A
>
struct subarray_counter
{
    enum { s = sizeof legal_array_counter<d,A>::type };
    typedef char (&type)[s+is_array<A>::value];
    static type x;
};

template <std::size_t d, std::size_t n>
struct strip
{
    enum { n_ = n };
    
    template <class E>
    static subarray_counter<d,E> f( E(&)[n_] );
};

template <std::size_t d, class A>
typename eval0<
    typename array_counter<d,A>::type
>::not_array dimension(A& a);


template <std::size_t n_>
struct charray1
{
    enum {n = n_};
    typedef char (&type)[n];
};

template <>
struct charray1<-1>
{
    typedef void type;
};

template <
    std::size_t d_
  , class A
>
struct next_array_counter
{
    enum {d = d_};
    static A a;
    enum {n = sizeof(A)/sizeof(a[0])};
    enum {s = sizeof( strip<d,n>::f(a).x ) -1};
    
    typedef typename charray1<s>::type type;
};

template <
    std::size_t d_
  , class A
>
struct legal_array_counter
{
    enum { d = d_ };
    
    typedef typename mpl::eval_if_c<
        d
      , next_array_counter<d-1,A>
      , dimension0<A>
    >::type type;
    
    static type x;
};

struct X
{
    operator void*() const;
    double operator[](std::size_t) const;
};

template <class X> struct whatis {};

int main()
{
    typedef X xt[1][2][3][4][5];
    xt a;
    (void)a;
    
    char a1[sizeof dimension<0>(a)] = { 0 }; // <--
    char a2[sizeof dimension<1>(a)] = { 0 };
    char a3[sizeof dimension<2>(a)] = { 0 };
    char a4[sizeof dimension<3>(a)] = { 0 };
    char a5[sizeof dimension<4>(a)] = { 0 };
#ifdef FAIL
    char a6[sizeof dimension<5>(a)] = { 0 };
#endif 

    std::cout << sizeof(a1) << ", " << sizeof(a2)
              << ", " << sizeof(a3) << ", " << sizeof(a4)
              << ", " << sizeof(a5)
              << '\n';

    return 0;
}



