Last active
October 13, 2015 02:18
-
-
Save eral/4123759 to your computer and use it in GitHub Desktop.
typenameof
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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; | |
} |
GCC の type_info::name() はabi::__cxa_demangle 後の値を目標しよう。
コンパイラ | バージョン |
---|---|
Visual Studio | 2012, 2010, 2008, 2005 |
Gcc | 4.8, 4.7, 4.6, 4.5, 4.4 |
Clang | 3.2, 3.1 |
上記は取り敢えず妥当な値が返ってくる。
ICC 13.0 に取り敢えず対応。
コンパイルタイム時に文字長が取れないのでstd::strlen
を使っています。
関数シグネチャ用確認コード
#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;
}
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 | ↑ |
関数シグネチャ用確認コード(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;
}
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 | ↑ |
戻り値を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
::utility::typenameof
"int"
type_info::name()
"i"
::utility::typenameof
"std::pair<int*, long int>"
type_info::name()
"St4pairIPilE"
::utility::typenameof
"hage::hige::huge<size_t*>::hege::hoge<std::pair<int*, long int> >"
type_info::name()
"N4hage4hige4hugeIPjE4hege4hogeISt4pairIPilEEE"
::utility::typenameof
"hage::hige::huge<size_t*>::hege::hoge<std::pair<int*, long int> >*"
type_info::name()
"PN4hage4hige4hugeIPjE4hege4hogeISt4pairIPilEEE"
そう言えば
type_info::name()
の値って特に決まってないのでしたね。