如何在可变的类模板中获得类型的索引?
How can I get the index of a type in a variadic class template?
我有一个可变引擎模板类:
template <typename ... Components> class Engine;
我想在编译时为每个组件分配一个数字,这相当于它们的顺序。这将在执行以下调用时返回:
template <typename Component> int ordinal();
例如:
Engine<PositionComponent, PhysicsComponent, InputComponent> engine;
被声明,调用:
engine.ordinal<PhysicsComponent>();
将返回1,类似的调用InputComponent而不是PhysicsComponent将返回2。
这是可能的吗?如果是,一个人会怎么做?
Mp11,这是一个简短的一行代码(一如既往):
template <typename... Components>
struct Engine {
template <typename Component>
static constexpr int ordinal() {
return mp_find<Engine, Component>::value;
}
};
注意,如果Component
不存在,这将返回sizeof...(Components)
。如果需要,您可以添加一个静态断言来验证这一点。
我的原始答案如下…
那么你想求Component
在Components...
中的指数?
template <typename... >
struct index;
// found it
template <typename T, typename... R>
struct index<T, T, R...>
: std::integral_constant<size_t, 0>
{ };
// still looking
template <typename T, typename F, typename... R>
struct index<T, F, R...>
: std::integral_constant<size_t, 1 + index<T,R...>::value>
{ };
用法:
template <typename Component>
size_t ordinal() { return index<Component, Components...>::value; }
作为构造,试图获得Component
不在Components...
中的ordinal
将导致编译错误。
我下面的目标是尽可能地保持在编译时领域。
这是删除一些样板文件的别名。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>
是一个表示组件索引的类型,而不是一个函数
为了完整起见,我添加了这个,它利用了c++ 11的constexpr功能和一些stl函数。我觉得它比其他解决方案更干净一点。
//Same type
template <typename Target,typename T,typename ...Rest>
constexpr typename std::enable_if<std::is_same<Target,T>::value, size_t>
_ordinal(){
return 0;
}
//Different types
template <typename Target,typename T,typename ...Rest>
constexpr typename std::enable_if<!std::is_same<Target,T>::value, size_t>
_ordinal(){
return 1+_ordinal<Target,Rest...>();
}
未测试:
template <int, typename>
constexpr int index_of() { return -1; } // type not found
template <int N, typename Component, typename Cur, typename... Components>
constexpr int index_of() {
return std::is_same<Component, Cur>::value ? N : index_of<N+1, Component, Components...>();
}
template <typename... Components>
template <typename Component>
constexpr int engine<Components...>::ordinal() {
return index_of<0, Component, Components...>();
}
我可以使用结构体,但是我发现这样更简洁(没有::type
的丑陋)。
如果您希望在未找到类型时出现编译时错误,请将ordinal
更改为:
template <typename... Components>
template <typename Component>
constexpr int engine<Components...>::ordinal() {
static_assert(index_of<0, Component, Components...>()!=-1, "invalid component");
return index_of<0, Component, Components...>();
}
- 在 std::variant 中按类型获取索引
- 类与枚举类作为索引类型
- 为什么C++数组索引值是有符号的,而不是围绕size_t类型构建的(或者我错了)
- 对于检查 >=0 终止条件时的循环索引类型
- 在索引和值类型上参数化的惯用向量类型
- 用于迭代不同类型的向量的索引类型
- 如何处理使用不同类型索引的不同库(例如 stl 和 eigen3)的混合(size_t、int、..)
- C++:从类型索引中获取超类类型索引
- 在运行时C++11 个索引模板参数包,以便访问第 N 种类型
- 通过索引将字节插入mutli字节类型
- 使用类型作为索引
- 如何确定未知类型数组的索引是否为空
- 使用查找表选择具有运行时索引的可变参数类型
- 将RGB颜色图像转换为OpenCV C 中的索引颜色图像类型
- 按索引将类类型元素从一个向量复制到另一个 c++
- <T> 在使用运算符+ 连接两个向量之前从类型向量中删除索引
- 获取类型列表中的类型的索引
- 获取 boost::variant 的类型索引与 boost::mpl
- 构造一个包含变量类型索引中第n个类型值的boost变量
- 类型索引元组