実行時に反復できるリスト内にコンパイル時の型情報 (名前、フィールドなど) を格納する必要があります。私は次のようなものを思いつきました:
#include <stdio.h>
struct Type
{
const char *m_szName;
Type *m_pNext;
};
struct TypeList
{
static Type *ms_pHead;
static Type *Push(Type *pHead)
{
Type *pNext(ms_pHead);
ms_pHead = pHead;
return pNext;
}
};
Type *TypeList::ms_pHead = 0;
template <typename T>
struct TypeHolder
{
static Type ms_kType;
};
#define _DECLARE_TYPE(_Name) \
template <> Type TypeHolder<_Name>::ms_kType = {#_Name, TypeList::Push(&ms_kType)};
struct A
{
float m_fField;
};
_DECLARE_TYPE(unsigned int);
_DECLARE_TYPE(float);
_DECLARE_TYPE(A);
int main()
{
Type *pType(TypeList::ms_pHead);
while (pType != 0)
{
printf("%s\n", pType->m_szName);
pType = pType->m_pNext;
}
return 0;
}
このように、新しい型を宣言し、同時に静的に登録するために必要なことは、コード内の任意の場所でマクロ _DECLARE_TYPE を使用することだけです。上記の例では、次のように出力されます。
A
float
unsigned int
MSVC9 では、すべて正常に動作し、「参照されていないデータの削除 (/OPT:REF)」を含む最適化をオンにするまで出力が得られます。それを行うと、上記のプログラムには出力がありません。TypeHolder、TypeHolder、TypeHolder がコード内で直接参照されていないことがわかりました。そのため、初期化の副作用に関係なく、リンカーがそれらを削除していると思います。静的初期化を使用した理由は、手動で呼び出す大きな関数を作成しなくても、コード内の任意の場所で型を宣言および登録できるためです。
TypeList::Push(TypeHolder<unsigned int>::ms_kType);
TypeList::Push(TypeHolder<float>::ms_kType);
TypeList::Push(TypeHolder<A>::ms_kType);
タイプごとに。
また、私のソリューションが幅広いコンパイラで動作するようにしたいので、MSVC でのみ動作する非標準の #pragma ディレクティブを使用したり、最適化をオフにしたりすることはオプションではありません。
すべてのタイプを別の場所 (マクロ内以外) に手動でリストする手間を省く方法はありますか?