1. ホーム
  2. c++

[解決済み] C++ テンプレート内の型名取得

2023-03-04 05:31:35

質問

私はテキスト データファイルを解析するためのテンプレート クラスを書いていますが、解析エラーの大部分はデータ ファイル内のエラーに起因すると思われます。

example.txt の解析に失敗しました。MySectiom]キーの値 ("notaninteger") は有効な int ではありません。

テンプレート関数に渡された引数とクラスのメンバ変数から、ファイル名、セクション名、およびキー名を調べることができますが、テンプレート関数が変換しようとしている型の名前を取得する方法がよくわかりません。

私の現在のコードは、単なる文字列やそのようなもののために特別化された、次のようになります。

template<typename T> T GetValue(const std::wstring &section, const std::wstring &key)
{
    std::map<std::wstring, std::wstring>::iterator it = map[section].find(key);
    if(it == map[section].end())
        throw ItemDoesNotExist(file, section, key)
    else
    {
        try{return boost::lexical_cast<T>(it->second);}
        //needs to get the name from T somehow
        catch(...)throw ParseError(file, section, key, it->second, TypeName(T));
    }
}

データファイルが使用する可能性のあるすべての型について、特定のオーバーロードを作成する必要はないでしょう。

すなわち、このコードは何度も呼び出され、ロード時間はすでにいくらか長くなっているので、完全にコンパイル時のソリューションが私が望むものです。

EDIT: OK これは私が考え出した解決策です。

私は以下の内容を含むtypes.hを持っています。

#pragma once
template<typename T> const wchar_t *GetTypeName();

#define DEFINE_TYPE_NAME(type, name) \
    template<>const wchar_t *GetTypeName<type>(){return name;}

それから、DEFINE_TYPE_NAMEマクロを使用して、扱う必要のある各タイプのcppファイル(例えば、最初にタイプを定義したcppファイル)で使用することができます。

リンカーは、それがどこかで定義されている限り、適切なテンプレート特殊化を見つけることができ、そうでなければリンカーエラーを投げるので、私は型を追加することができます。

どのように解決するのですか?

Jesse Bederの解決策がベストだと思いますが、もしtypeidが与える名前が気に入らない場合(例えばgccはマングルドネームを与えると思います)、以下のようにすることができます。

template<typename T>
struct TypeParseTraits;

#define REGISTER_PARSE_TYPE(X) template <> struct TypeParseTraits<X> \
    { static const char* name; } ; const char* TypeParseTraits<X>::name = #X


REGISTER_PARSE_TYPE(int);
REGISTER_PARSE_TYPE(double);
REGISTER_PARSE_TYPE(FooClass);
// etc...

そして、以下のように使用します。

throw ParseError(TypeParseTraits<T>::name);

EDITです。

また、この2つを組み合わせることもできます。 name をデフォルトで呼び出す関数に変更します。 typeid(T).name() をデフォルトで呼び出し、それが許容できない場合のみ特別化するようにします。