typeid(T).name() に関して

メタプログラミングとかのデバッグ用に、型名を表示させたい場合ってありますよね。
そういう場合は、typeid 演算子を使って、

#include <typeinfo>
#include <iostream>

int main()
{
  std::cout << typeinfo(int).name() << std::endl;
}

とかやればいい訳ですが、ここで問題が一つあります。
標準の規格はよく知りませんが、 gcc の場合、参照型への typeid 呼び出し結果が、非参照型への typeid 結果と同じになってしまうのです:
http://ideone.com/A5TG6SQT

#include <typeinfo>
#include <iostream>
 
using namespace std;
 
int main()
{
  cout << boolalpha << ( typeid(int) == typeid(int&) ) << endl;
}

結果:

true


この問題を回避するためには、例えば、
http://ideone.com/tPFR3iU3

#include <boost/type.hpp>
#include <typeinfo>
#include <iostream>
 
using namespace std;
 
int main()
{
  cout << typeid(int).name() << endl;
  cout << typeid(int&).name() << endl;
  cout << typeid(boost::type<int>).name() << endl;
  cout << typeid(boost::type<int&>).name() << endl;
}

のように、テンプレートのパラメータとして渡してあげれば、

i
i
N5boost4typeIiEE
N5boost4typeIRiEE

といった感じに、きちんと区別できるようになります。


とはいえ N5boost4typeIiEE のままでは読みにくい。
そういう場合は、
http://ideone.com/lutHYURq

#include <typeinfo>
#include <cxxabi.h> // for abi::__cxa_demangle
 
// メモリリークするので要改良
char* demangle(const char *demangled)
{
  int status;
  return abi::__cxa_demangle(demangled, 0, 0, &status);
}

// T 型の型名を取得
template<typename T>
char* typename_of()
{
  return demangle( typeid(T).name() );
}
 
#include <iostream>
#include <boost/type.hpp>
using namespace std;
 
int main()
{
  cout << typename_of< boost::type<int > >() << endl;
  cout << typename_of< boost::type<int&> >() << endl;
}

のようにデマングルしてあげると、

boost::type<int>
boost::type<int&>

って感じになり、読みやすくすることが出来ます(参考: http://0xcc.net/blog/archives/000095.html )。

Boost.MPLは楽しそうだけどデバッグが難しそう、そう感じていた人は、こうやって型名を表示させながらテストしてみると面白いかもしれませんね!


といっても typeid(T).name() は、あくまでデバッグ用の機能なので、実際のコーディングで活用するのはダウトです。お気をつけ下さい。