コードで使用するマクロの検索と展開を担当するプリプロセッサが言語自体を認識していないため、コードが機能しません。それは単なるテキストパーサーです。関数テンプレートにある STRINGIFY(T) を見つけて、そのテンプレートに型を与えるずっと前に展開します。結局のところ、残念ながら、期待した型名ではなく、常に "T" が返されます。
litbが示唆したように、渡した型名を返すこの「getTypeName」関数テンプレートを (ひどく) 実装しました。
#include <iostream>
template <typename _Get_TypeName>
const std::string &getTypeName()
{
static std::string name;
if (name.empty())
{
const char *beginStr = "_Get_TypeName =";
const size_t beginStrLen = 15; // Yes, I know...
// But isn't it better than strlen()?
size_t begin,length;
name = __PRETTY_FUNCTION__;
begin = name.find(beginStr) + beginStrLen + 1;
length = name.find("]",begin) - begin;
name = name.substr(begin,length);
}
return name;
}
int main()
{
typedef void (*T)(int,int);
// Using getTypeName()
std::cout << getTypeName<float>() << '\n';
std::cout << getTypeName<T>() << '\n'; // You don't actually need the
// typedef in this case, but
// for it to work with the
// typeid below, you'll need it
// Using typeid().name()
std::cout << typeid(float).name() << '\n';
std::cout << typeid(T).name() << '\n';
return 0;
}
上記のコードは、GCC フラグ -s (「バイナリからすべてのシンボルを削除する」) を有効にして、次の出力を生成します。
float
void (*)(int, int)
f
PFviiE
つまり、 getTypename() はかなり優れた仕事をしますが、その厄介な文字列解析ハックを犠牲にしています (私は知っています、それは非常に醜いです)。
考慮すべきいくつかの点:
- コードは GCC のみです。別のコンパイラに移植する方法がわかりません。おそらく、非常にきれいな関数名を生成する機能を備えているものは他にほとんどありません。私が検索したところ、MSVC++ には機能がありません。
- 新しいバージョンで GCC フォーマット
__PRETTY_FUNCTION__
が異なる場合、文字列の一致が壊れる可能性があるため、修正する必要があります。これと同じ理由で、 getTypeName()はデバッグに適している可能性があることも警告します (それでも、デバッグには適していない可能性さえあります)。またはそのようなもの(わかりません。誰かがどう思うかを推測するだけです..)。デバッグのためにのみ使用し、優先的にリリース ビルドでは呼び出さないでください (マクロを使用して無効にします)。これにより、使用__PRETTY_FUNCTION__
しないため、コンパイラはその文字列を生成しません。
- 私は間違いなく専門家ではありません。奇妙な型が原因で文字列の照合が失敗する可能性があるかどうかはわかりません。この記事を読んでいる方で、そのような事例をご存知の方がいらっしゃいましたらコメントをお願いしたいです。
- コードは静的 std::string を使用します。これは、何らかの例外がコンストラクターまたはデストラクターからスローされた場合、それが catch ブロックに到達する方法がなく、ハンドルされない例外が発生することを意味します。std::strings がそれを実行できるかどうかはわかりませんが、実行すると問題が発生する可能性があることに注意してください。メモリを解放するにはデストラクタが必要なので使用しました。ただし、そのために独自のクラスを実装して、割り当ての失敗以外に例外がスローされないようにし (これはかなり致命的ですよね? そうです...)、単純な C 文字列を返すことができます。
- typedef を使用すると、次のような奇妙な結果が得られる場合があります (何らかの理由で、サイトがこのスニペットの書式設定を壊しているため、この貼り付けリンクを使用しています): http://pastebin.com/f51b888ad
これらの欠点にもかかわらず、確かに速いと言いたいです。同じ型名を 2 回目に検索すると、その名前を含むグローバルな std::string への参照を選択する必要があります。また、以前に提案されたテンプレートの特殊化メソッドと比較して、テンプレート自体以外に宣言する必要があるものは何もないため、非常に使いやすくなっています。