I have run into a scenario in which I have a list of classes in a variadic template list, and, given a type (Target_), I wish to find the class in the list (ContainingClass_) that typedefs Target_ as ContainingClass_::Class.
Here is my current, brute force implementation:
#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;
}
The problem with this is that it depends on std::tuple and does two linear searches: one for the existence check (using the first helper meta-function) and one to get the type (using std::tuple_element).
I would Ideally like to get all of this in one go, with no need for the two helper meta-functions and std::tuple; is that practical? If not, any improvements to my implementation would be appreciated.
Aucun commentaire:
Enregistrer un commentaire