c ++17のconstexprifを使用すると、インデックスルックアップ関数のはるかに読みやすくわかりやすい実装を取得できます(ここで他の答えに頭を悩ませることはできませんでした)。
template<typename Target, typename ListHead, typename... ListTails>
constexpr size_t getTypeIndexInTemplateList()
{
if constexpr (std::is_same<Target, ListHead>::value)
return 0;
else
return 1 + getTypeIndexInTemplateList<Target, ListTails...>();
}
これは次のように使用できます。
size_t index = getTypeIndexInTemplateList<X, Foo,Bar,X,Baz>(); // this will return 2
または、さまざまにテンプレート化されたタイプがあり、その中にインデックスを取得したい場合は、次のようになります。
template<typename... Types>
class Container
{
public:
size_t getIndexOfType<typename T>() { return getTypeIndexInTemplateList<T, Types...>(); }
};
...
Container<Foo, Bar, X, Baz> container;
size_t container.getIndexOfType<X>(); // will return 2
それが機能する方法は、リストから型を再帰的に削除することです。したがって、最初の例の呼び出し順序は基本的に次のとおりです。
getTypeIndexInTemplateList<X, Foo, Bar,X,Baz>() // ListHead = Foo, ListTails = Bar,X,Baz
getTypeIndexInTemplateList<X, Bar, X,Baz>() // ListHead = Bar, ListTails = X, Baz
getTypeIndexInTemplateList<X, X, Baz>() // ListHead = X, so now we return. Recursive addition takes care of calculating the correct index
関数はconstexprであるため、これはすべてコンパイル時に実行され、実行時には定数になります。
リストに存在しない型を要求すると、テンプレート引数が少なすぎる関数を呼び出そうとするため、コンパイルエラーが発生します。そしてもちろん、タイプが複数回存在する場合、これはリスト内のタイプの最初のインスタンスのインデックスを返すだけです。