#include <string>
#include <typeinfo>

#ifdef __GNUG__

    #include <cxxabi.h>
    #include <cstdlib>
    #include <memory>

    template< typename T > std::string type_name()
    {
        int status ;
        std::unique_ptr< char[], decltype(&std::free) > buffer(
            __cxxabiv1::__cxa_demangle( typeid(T).name(), nullptr, 0, &status ), &std::free ) ;
        return status==0 ? buffer.get() : "__cxa_demangle error" ;
    }

#else // !defined __GNUG__

    template< typename T > std::string type_name() { return typeid(T).name() ; }

#endif //__GNUG__

template< typename T > std::string type_name( const T& ) { return type_name<T>() ; }


#define print_type_name(var) ( std::cout << #var << " is of type " << type_name(var) << "\n\n" )

#include <iostream>

int main()
{
    int array2D[3][3] = { { 1,  5,  6 }, { 45, 65, 65}, { 78, 10, 99 } } ;

    auto ptr = array2D+1 ;

    print_type_name( ptr ) ; // ptr is of type int (*) [3]

    print_type_name( *ptr ) ; // *ptr is of type int [3]

}
