#include <string>
#include <iostream>
#include <iterator>
#include <type_traits>

template < typename T, std::size_t N >
constexpr std::size_t size( T(&)[N] ) { return N ; }

int main()
{
    const std::string first[] = { "a", "be", "see" } ;

    std::cout << "array 'first' size: " << size(first) << ' ' ;

    // std::end() overload for arrays uses the same technique
    std::cout << std::end(first) - std::begin(first) << ' ' ;

    // more of the same
    std::cout << std::extent< decltype(first) >::value << '\n' ;


    const int second[][6] = { {0,1}, {2,3,4}, {5}, {6,7,8,9}, {} } ;
    using array_type = decltype(second) ;

    std::cout << "array 'second' rank: " << std::rank<array_type>::value << ", "
               << "nrows: " << std::extent<array_type>::value << ", "
               << "ncols: " << std::extent<array_type,1>::value << '\n' ;
}
