#テンプレートを書いていて、推論された型を確認したい
テンプレートを記述していると
「この引数を与えたときには、T
がどう推論されるのか?」
なんて思うことは良くありますよね?
嗚呼、そんなとき、どーしたらよいのでしょーか?
たとえば
template < typename T >
void f(T&&){}
void g(int const&){};
int main(){
f(g);
}
この場合のT
がどう推論されるのか知りたい!
と思ったとき、どうしますか?
- 諦める
- IDEに頼る
- typeid.name()を使う
- Boost.Typeindexを使う
- Attributeを使う(C++14)
#IDEに頼る
フォーカスすると情報が表示されるのを利用する
IDEを使っている場合は概ねこれで事足りる
#typeid.name()を使う
ヘッダをインクルードして
この方法では実行時までわからない型情報を表示することができるので
RTTI(Run Time Type Identifier)
と呼ばれている
#include <iostream>
#include <typeinfo>
using namespace std;
template < typename T >
void f(T&&){ cout << typeid(T).name() << endl;}
void g(int const&){};
int main(){
f(g);
}
実行結果
FvRKiE
めでたしめでたし...
いやまて、何だこの文字列は!!
typeidで取得できる型名はそのままではマングルされていて
容易に読むことはできないのである(Microsoft コンパイラは読める文字列を返す)
デマングルするには次のようにする
#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
using namespace std;
template < typename T >
void f(T&&){
const type_info& id = typeid(T);
int stat;
char *name = abi::__cxa_demangle(id.name(),0,0,&stat);
if( name!=NULL ) {
if( stat==0 ) { // ステータスが0なら成功
printf("T = %s",name);
}
free(name); // freeする必要がある
}
}
void g(int const&){};
int main(){
f(g);
}
#Boost.Typeindex
Boost.Typeindexを使えば環境によってマングルされていたり
されていなかったりすることはないと思われる
#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
template < typename T >
void f(T&&){ cout << boost::typeindex::type_id_with_cvr<T>().pretty_name() << endl;}
void g(int const&){};
int main(){
f(g);
}
実行結果
void (&)(int const&)
めでたしめでたし...
しかし、ちょっと待てよ
これは面倒ではないか?
もっと手軽な方法がC++14には存在する
#Attribute [[deprecated]]
[[deprecated]]
指定してしまうのだ!
そうすれば非推奨された関数が使用されたことを悟ったコンパイラは
警告文を出す
そう、引数の型名も同時に表示してくれる!
template < typename T >
[[deprecated]] void f(T&&){}
void g(int const&){};
int main(){
f(g);
}
警告文
prog.cc: In function 'int main()':
prog.cc:8:8: warning: 'void f(T&&) [with T = void (&)(const int&)]' is deprecated [-Wdeprecated-declarations]
f(g);
^
>prog.cc:3:21: note: declared here
[[deprecated]] void f(T&&){}
^
この方法ではヘッダをインクルードすることも
デバッグ出力を書くことも
もはや必要が無い!!