Skip to content

Instantly share code, notes, and snippets.

@eral
Last active October 13, 2015 02:18
Show Gist options
  • Save eral/4123759 to your computer and use it in GitHub Desktop.
Save eral/4123759 to your computer and use it in GitHub Desktop.
typenameof
//https://gist.github.com/eral/4123759
#if defined(__INTEL_COMPILER)
# include <cstring>
#endif
#if defined(__GNUC__)
# include <cxxabi.h>
#endif
#include <string>
#include <utility>
#include <iterator>
#include <algorithm>
#include <iostream>
#include <typeinfo>
#include <cstddef>
#if (0 < _MSC_VER)
//VC++ 2012 2010 2008 2005
//const char *__cdecl utility::detail::typenameof_::typenameof<int>(int *)
# define UTILITY_TYPENAMEOF_ANALYZE_DIRECT_INSERTION
#elif defined(__INTEL_COMPILER)
//ICC 13.0.1
//const char *utility::detail::typenameof_::typenameof(T *) [with T = int]
# define UTILITY_TYPENAMEOF_ANALYZE_NOTE_ARGUMENT_ONLY
#elif defined(__clang__)
# if ((4 <= __clang_major__) || ((3 == __clang_major__) && (1 <= __clang_minor__)))
//Clang 3.2 3.1
//const char *utility::detail::typenameof_::typenameof(T *) [T = int]
# define UTILITY_TYPENAMEOF_ANALYZE_NOTE_ARGUMENT_ONLY
# else
//Clang 3.0
//const char *utility::detail::typenameof_::typenameof(int *)
# define UTILITY_TYPENAMEOF_ANALYZE_DIRECT_INSERTION
# endif
#elif defined(__GNUC__)
//GCC 4.8.0 4.7.2 4.6.3 4.5.3 4.4.7
//const char *utility::detail::typenameof_::typenameof(T*) [with T = int]
# define UTILITY_TYPENAMEOF_ANALYZE_NOTE_ARGUMENT_ONLY
#endif
#if (0 < _MSC_VER)
# define UTILITY_TYPENAMEOF_PRETTY_FUNCTION __FUNCSIG__
#else
# define UTILITY_TYPENAMEOF_PRETTY_FUNCTION __PRETTY_FUNCTION__
#endif
namespace utility {
namespace detail { namespace typenameof_ {
template <typename T>
struct range {
T begin;
T end;
range(T be, T en): begin(be), end(en) {}
};
template <std::size_t N>
class string : private string<N-1> {
typedef string<N-1> super_type;
char m_value;
protected:
string(const char *begin, const char *end): super_type(begin, end), m_value((begin+N-1 < end)? begin[N-1]: '\0') {}
public:
const char *get() {
return reinterpret_cast<const char *>(this);
}
string(const range<const char *> &src): super_type(src.begin, src.end), m_value('\0') {}
};
template <>
class string<0> {
protected:
string(const char *, const char *) {}
public:
};
range<const char *> analyze(const char *begin, const char *end, char begin_mark, std::size_t begin_ofst, char end_mark, std::size_t end_ofst) {
return range<const char *>(&*(std::find(begin, end, begin_mark) + begin_ofst)
, &*std::find(std::reverse_iterator<const char *>(end)
, std::reverse_iterator<const char *>(begin)
, end_mark
) + end_ofst
);
}
#if defined(UTILITY_TYPENAMEOF_ANALYZE_DIRECT_INSERTION)
template<std::size_t N>
range<const char *> analyze(const char (&pretty_function)[N]) {
return analyze(pretty_function, pretty_function + N, '(', 1, '*', 0);
}
#elif defined(UTILITY_TYPENAMEOF_ANALYZE_NOTE_ARGUMENT_ONLY)
# if defined(__INTEL_COMPILER)
range<const char *> analyze(const char *pretty_function) {
std::size_t N = std::strlen(pretty_function) + 1;
return analyze(pretty_function, pretty_function + N, '=', 2, ']', 0);
}
# else
template<std::size_t N>
range<const char *> analyze(const char (&pretty_function)[N]) {
return analyze(pretty_function, pretty_function + N, '=', 2, ']', 0);
}
# endif
#else
range<const char *> analyze(const char *pretty_function) {
std::size_t N = std::strlen(pretty_function) + 1;
return range(pretty_function, pretty_function + N);
}
#endif
template <typename T>
const char *typenameof(T*) {
#if defined(__INTEL_COMPILER)
range<const char *> typename_range = analyze(UTILITY_TYPENAMEOF_PRETTY_FUNCTION);
static std::string typename_string(typename_range.begin, typename_range.end);
return typename_string.c_str();
#else
range<const char *> typename_range = analyze(UTILITY_TYPENAMEOF_PRETTY_FUNCTION);
static string<sizeof(UTILITY_TYPENAMEOF_PRETTY_FUNCTION)> typename_string(typename_range);
return typename_string.get();
#endif
}
}}
template <typename T>
const char *typenameof() {
return detail::typenameof_::typenameof<T>(0);
}
template <typename T>
const char *typenameof(const T &) {
return detail::typenameof_::typenameof<T>(0);
}
}
#undef UTILITY_TYPENAMEOF_ANALYZE_DIRECT_INSERTION
#undef UTILITY_TYPENAMEOF_ANALYZE_NOTE_ARGUMENT_ONLY
#undef UTILITY_TYPENAMEOF_PRETTY_FUNCTION
#if (0 < _MSC_VER)
std::string demangle(const std::string &src) {
return src;
}
#elif defined(__GNUC__)
std::string demangle(const std::string &src) {
int status;
char *buf = abi::__cxa_demangle(src.c_str(), 0, 0, &status);
std::string result(buf);
free(buf);
return result;
}
#else
std::string demangle(const std::string &src) {
return src;
}
#endif
namespace hage { namespace hige {
template <typename T>
class huge {
public:
class hege {
public:
template <typename U>
struct hoge {
void test() {
std::cout << "|`::utility::typenameof()` |`\"" << ::utility::typenameof(this) << "\"`|" << std::endl;
std::cout << "|`demangle(type_info::name())`|`\"" << demangle(typeid(this).name()) << "\"`|" << std::endl;
}
};
};
};
}}
int main(void)
{
std::cout << "|`::utility::typenameof<>` |`\"" << ::utility::typenameof<int>() << "\"`|" << std::endl;
std::cout << "|`demangle(type_info::name())`|`\"" << demangle(typeid(int).name()) << "\"`|" << std::endl;
{
typedef ::std::pair<int *, long> test_type;
test_type instance;
std::cout << "|`::utility::typenameof()` |`\"" << ::utility::typenameof(instance) << "\"`|" << std::endl;
std::cout << "|`demangle(type_info::name())`|`\"" << demangle(typeid(test_type()).name()) << "\"`|" << std::endl;
}
{
typedef ::hage::hige::huge< ::std::size_t *>::hege::hoge< ::std::pair<int *, long> > test_type;
std::cout << "|`::utility::typenameof<>` |`\"" << ::utility::typenameof<test_type>() << "\"`|" << std::endl;
std::cout << "|`demangle(type_info::name())`|`\"" << demangle(typeid(test_type).name()) << "\"`|" << std::endl;
test_type instance;
instance.test();
}
return 0;
}
@eral
Copy link
Author

eral commented Nov 22, 2012

Visual Studio 2008 int
::utility::typenameof "int "
type_info::name() "int"
Visual Studio 2008 struct std::pair<int *,long>
::utility::typenameof "struct std::pair<int *,long> "
type_info::name() "struct std::pair<int *,long>"
Visual Studio 2008 struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> >
::utility::typenameof "struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> > "
type_info::name() "struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> >"
Visual Studio 2008 struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> > *
::utility::typenameof "struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> > *"
type_info::name() "struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> > *"

最後に空白が乗る事があるけど、取り敢えずVS2008は問題無し。

@eral
Copy link
Author

eral commented Nov 26, 2012

GCC 4.3.4 int
::utility::typenameof "int"
type_info::name() "i"
GCC 4.3.4 struct std::pair<int *,long>
::utility::typenameof "std::pair<int*, long int>"
type_info::name() "St4pairIPilE"
GCC 4.3.4 struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> >
::utility::typenameof "hage::hige::huge<size_t*>::hege::hoge<std::pair<int*, long int> >"
type_info::name() "N4hage4hige4hugeIPjE4hege4hogeISt4pairIPilEEE"
GCC 4.3.4 struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> > *
::utility::typenameof "hage::hige::huge<size_t*>::hege::hoge<std::pair<int*, long int> >*"
type_info::name() "PN4hage4hige4hugeIPjE4hege4hogeISt4pairIPilEEE"

そう言えばtype_info::name()の値って特に決まってないのでしたね。

@eral
Copy link
Author

eral commented Mar 25, 2013

GCC の type_info::name() はabi::__cxa_demangle 後の値を目標しよう。

@eral
Copy link
Author

eral commented Mar 26, 2013

コンパイラ バージョン
Visual Studio 2012, 2010, 2008, 2005
Gcc 4.8, 4.7, 4.6, 4.5, 4.4
Clang 3.2, 3.1

上記は取り敢えず妥当な値が返ってくる。

@eral
Copy link
Author

eral commented Mar 27, 2013

ICC 13.0 に取り敢えず対応。
コンパイルタイム時に文字長が取れないのでstd::strlenを使っています。

@eral
Copy link
Author

eral commented Mar 29, 2013

関数シグネチャ用確認コード

#include <string>
#include <iostream>

namespace utility {
    namespace detail {
        namespace typenameof_ {
            template <typename T>
            std::string typenameof(T*) {
#if (0 < _MSC_VER)
                return __FUNCSIG__;
#else
                return __PRETTY_FUNCTION__;
#endif
            }
        }
    }

    template <typename T>
    std::string typenameof() {
        return detail::typenameof_::typenameof<T>(0);
    }
    template <typename T>
    std::string typenameof(const T &) {
        return detail::typenameof_::typenameof<T>(0);
    }
}

int main(void)
{
    std::cout << ::utility::typenameof<int>() << std::endl;
    std::cout << ::utility::typenameof(0) << std::endl;

    return 0;
}

@eral
Copy link
Author

eral commented Mar 29, 2013

GCC __PRETTY_FUNCTION__
GCC 4.8.0 std::string utility::detail::typenameof_::typenameof(T*) [with T = int; std::string = std::basic_string<char>]
GCC 4.7.2
GCC 4.6.3 std::string utility::detail::typenameof_::typenameof(T*) [with T = int, std::string = std::basic_string<char>]
GCC 4.5.x
GCC 4.4.x std::string utility::detail::typenameof_::typenameof(T*) [with T = int]
Clang __PRETTY_FUNCTION__
Clang 3.2.x std::string utility::detail::typenameof_::typenameof(T *) [T = int]
Clang 3.1.x
Clang 3.0.x std::string utility::detail::typenameof_::typenameof(int *)
ICC __PRETTY_FUNCTION__
ICC 13.0.1 std::basic_string<char, std::char_traits<char>, std::allocator<char>> utility::detail::typenameof_::typenameof(T *) [with T = int]
VC++ __FUNCSIG__
VC++ 2012 class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl utility::detail::typenameof_::typenameof<int>(int *)
VC++ 2010
VC++ 2008
VC++ 2005

@eral
Copy link
Author

eral commented Mar 29, 2013

関数シグネチャ用確認コード(not std::string version)

#include <iostream>

namespace utility {
    namespace detail {
        namespace typenameof_ {
            template <typename T>
            const char *typenameof(T*) {
#if (0 < _MSC_VER)
                return __FUNCSIG__;
#else
                return __PRETTY_FUNCTION__;
#endif
            }
        }
    }

    template <typename T>
    const char *typenameof() {
        return detail::typenameof_::typenameof<T>(0);
    }
    template <typename T>
    const char *typenameof(const T &) {
        return detail::typenameof_::typenameof<T>(0);
    }
}

int main(void)
{
    std::cout << ::utility::typenameof<int>() << std::endl;
    std::cout << ::utility::typenameof(0) << std::endl;

    return 0;
}

@eral
Copy link
Author

eral commented Mar 29, 2013

GCC __PRETTY_FUNCTION__
GCC 4.8.0 const char *utility::detail::typenameof_::typenameof(T*) [with T = int]
GCC 4.7.2
GCC 4.6.3
GCC 4.5.x
GCC 4.4.x
Clang __PRETTY_FUNCTION__
Clang 3.2.x const char *utility::detail::typenameof_::typenameof(T *) [T = int]
Clang 3.1.x
Clang 3.0.x const char *utility::detail::typenameof_::typenameof(int *)
ICC __PRETTY_FUNCTION__
ICC 13.0.1 const char *utility::detail::typenameof_::typenameof(T *) [with T = int]
VC++ __FUNCSIG__
VC++ 2012 const char *__cdecl utility::detail::typenameof_::typenameof<int>(int *)
VC++ 2010
VC++ 2008
VC++ 2005

@eral
Copy link
Author

eral commented Mar 29, 2013

戻り値をstd::stringからconst char *に変更。
これに伴いTMPにて文字長が取得出来無いICCに於いて、関数内static変数てにメモリアロケートが走ると言う酷い構成に為りました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment