私はvariadicテンプレートリストにクラスのリストを持っているシナリオを実行しました。タイプ(Target_
)を指定した場合、リスト内のクラス(ContainingClass_
)はとしてContainingClass_::Class
となります。ここでC++で与えられた型のtypedefを持つ型リストから型を返すメタ関数を書く11
は私の現在、強引な実装である:
#include <iostream>
#include <cstdlib>
#include <type_traits>
#include <tuple>
template <uint32_t ID_, class Class_>
struct ContainingClass
{
using Class = Class_;
static constexpr uint32_t id() { return ID_; }
};
// Get the index of a type in a type list, or -1 on error (So that we only get the important static_assert).
template <typename Target_, typename ...List_>
struct IndexOf : std::integral_constant<int, -1> {};
template <typename Target_, typename NotTarget_, typename ...List_>
struct IndexOf<Target_, NotTarget_, List_...> : std::integral_constant<std::size_t, 1 + IndexOf<Target_, List_...>::value> {};
template <typename Target_, typename ...List_>
struct IndexOf<Target_, Target_, List_...> : std::integral_constant<std::size_t, 0> {};
// Check if a type exists in a typelist.
template <typename Target_, typename... List_>
struct TypeExists;
template <typename Target_>
struct TypeExists<Target_> : std::false_type {};
template <typename Target_, typename... List_>
struct TypeExists<Target_, Target_, List_...> : std::true_type {};
template <typename Target_, typename NotTarget_, typename... List_>
struct TypeExists<Target_, NotTarget_, List_...> : TypeExists<Target_, List_...> {};
// **THE META-FUNCTION THAT THE QUESTION IS ABOUT**
// Find the ContaingClass that typedefs Target_ as "Class" inside of it.
template <class Target_, class ...ContainingClasses_>
struct ContainingClassFinder
{
static_assert(TypeExists<Target_, typename ContainingClasses_::Class...>::value, "No ContainingClass found for Target_.");
using ContainingClass = typename std::tuple_element<IndexOf<Target_, typename ContainingClasses_::Class...>::value,
std::tuple<ContainingClasses_...>>::type;
};
using namespace std;
// Use the meta function to return the id of the ContainingClass that contains a type.
template <class Target_, class ...ContainingClasses_>
uint32_t get_containing_id(ContainingClasses_...)
{
return ContainingClassFinder<Target_, ContainingClasses_...>::ContainingClass::id();
}
struct Foo {};
struct Bar {};
struct Test {};
struct NonExistent {};
int main()
{
// Prove that the right class was found be printing its ID out.
// Prints 2.
cout << get_containing_id<Test>(ContainingClass<0, Foo>{}, ContainingClass<1, Bar>{}, ContainingClass<2, Test>{}) << endl;
// Causes static_assert.
//cout << get_containing_id<NonExistent>(ContainingClass<0, Foo>{}, ContainingClass<1, Bar>{}, ContainingClass<2, Test>{}) << endl;
return EXIT_SUCCESS;
}
これに伴う問題は、それがstd::tuple
に依存し、2つの直線を検索していることである:存在チェックのための1つの(第1のヘルパーメタ機能を使用します) 1つはタイプを取得する(std::tuple_element
を使用)。
私は理想的には、2つのヘルパーメタ機能と、std::tuple
を必要とせずに、一度にすべてを取得したいと思います。実用的ですか?そうでない場合は、私の実装の改善が認められるでしょう。
注:
1.このメタ関数は、ライブラリの実装の詳細として使用されます。 Boostはオプションではありません。
2.メタ関数の結果は、型でなければなりません。具体的には、対象の型が見つかった型を含む型である必要があります。クラスのid()を取得することは、メタ関数が動作していることを示します。メタ機能により、
3.、私は[更新]これが私のために働いている<type_traits>
再改造の代わりに、おそらくBoost.Hanaをご覧ください。 –
@KerrekSB私に思い出させることに感謝します。私はこれが図書館の一部であると言及することを忘れていました。ブーストは単に選択肢ではありません。 – rationalcoder
私の更新された答えを見てください:コンパイルし、意図したとおりに動作します –