我下面的目标是尽可能地保持在编译时领域。
这是删除一些样板的别名。 std::integral_constant 是一个很棒的 std 类型,它存储编译时确定的整数类型:
template<std::size_t I>
using size=std::integral_constant<std::size_t, I>;
接下来,一个index_of类型,还有一个更容易使用的index_of_t:
template<class...>struct types{using type=types;};
template<class T, class Types>struct index_of{};
template<class T, class...Ts>
struct index_of<T, types<T, Ts...>>:size<0>{};
template<class T, class T0, class...Ts>
struct index_of<T, types<T0, Ts...>>:size<
index_of<T,types<Ts...>>::value +1
>{};
这个别名返回一个纯std::integral_constant,而不是从它继承的类型:
template<class T, class...Ts>
using index_of_t = size< index_of<T, types<Ts...>>::value >;
最后是我们的函数:
template <class Component>
static constexpr index_of_t<Component, Components...>
ordinal() const {return{};}
它不仅是constexpr,它还返回一个将其值编码为其类型的值。 size<?> 有一个 constexpr operator size_t() 和一个 operator(),所以你可以在大多数需要无缝整数类型的地方使用它。
你也可以使用:
template<class Component>
using ordinal = index_of_t<Component, Components...>;
现在ordinal<Component> 是表示组件索引的类型,而不是函数。