如何区分存储在模板化类中的类型
How to distinguish the type stored in a templated class
假设我有一个类,它假装是其模板包中的一个类型,我如何获得函数中一个模板参数所在的索引或当前索引指向的类型?
template<typename... Vs>
struct TypeIndex {
int index_of_type;
void some_function() {
cout << static_cast<get_type_from_index()> (some_member);
}
};
我知道这里需要进行一些类专门化,但我不能完全理解这将如何在代码中实现。任何帮助都将是伟大的,谢谢!
获取函数中一个模板参数所在的索引
有200万种方法可以做到这一点。这里有一个:
// base case is "not found"
template<size_t N, class T, class... Ts>
struct index_of_impl : std::integral_constant<std::size_t, std::size_t(-1)> {};
template<size_t N, class T, class... Ts>
struct index_of_impl<N, T, T, Ts...> : std::integral_constant<std::size_t, N> {};
template<size_t N, class T, class U, class... Ts>
struct index_of_impl<N, T, U, Ts...> : index_of_impl<N+1, T, Ts...> {};
template<class T, class... Ts>
struct index_of : index_of_impl<0, T, Ts...> {};
当前索引指向的类型
索引的值只有在运行时才知道,C++是静态类型的,所以这是不可能的。
对于编译时索引来说,这是微不足道的:
template<size_t I, class... Ts>
using at = std::tuple_element_t<I, std::tuple<Ts...>>;
但是
boost::variant
是如何用apply_visitor
实现这一点的呢作用
apply_visitor
的想法是将其编译为类似switch
的结构:
// pseudocode
switch(index) {
case 0:
return visitor(get<0>(variant));
break;
case 1:
return visitor(get<1>(variant));
break;
// etc.
};
请注意,visitor
需要处理变体中的每个类型,并在每种情况下返回相同的类型,这就是上述工作的原因。
当然,在现实中,如果类型的可能数量是无界的,你就不能写switch
(在C++03中——没有可变模板——boost::variant
显然对它可以处理的类型数量有上限,所以如果他们愿意,他们可以直接写switch
)。最简单的方法是简单地尝试每个索引,直到找到正确的索引。草图:
template<size_t N>
struct impl {
template<class Visitor, class Variant>
decltype(auto) apply(Visitor visitor, const Variant& variant){
if(variant.index == N) return visitor(get<N>(variant));
return impl<N-1>::apply(visitor, variant);
}
};
template<>
struct impl<0>{
template<class Visitor, class Variant>
decltype(auto) apply(Visitor visitor, const Variant& variant){
assert(variant.index == 0);
return visitor(get<0>(variant));
}
};
template<class Visitor, class Variant>
decltype(auto) apply_visitor(Visitor visitor, const Variant& variant){
return impl<variant_size<Variant>::value>::apply(visitor, variant);
}
有更有效的方法(例如,进行二进制搜索或使用跳转表)。
下面的类使用代码来回答您的另一个问题。我没有包括它,因为依赖它的析构函数调度还没有实现。
使用方式类似于:using my_type = pack_type_at<index, Vs...>::type;
,其中index
是编译时可用的整数,类似于模板参数。
投票前请注意:这只是针对编译时索引,所以它不能完全回答这个问题。在其他地方,我说这个任务是"不平凡的",因为需要使用运行时索引以某种方式找到并运行与其中一个包索引相对应的适当函数重载。
template <int IDX, int CURI, bool ATIDX, typename V, typename ...Vs>
struct pack_type_at_helper {
typedef typename pack_type_at_helper<IDX, CURI+1, CURI+1==IDX, Vs...>::type type;
};
template <int IDX, int CURI, typename V, typename ...Vs>
struct pack_type_at_helper<IDX, CURI, true, V, Vs...> {
typedef V type;
};
template <int IDX, typename ...Vs>
struct pack_type_at {
typedef typename pack_type_at_helper<IDX, 0, IDX==0, Vs...>::type type;
};
- ArduinoJson 6.15.2:JsonObject没有命名类型
- 防止主数据类型C++的隐式转换
- 大量序列中核苷酸类型的快速计数
- 如何从C++中的依赖类型中获得它所依赖的类型
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如何获取std::result_of函数的返回类型
- 从父命名空间重载类型
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- Openssl 1.1.1d无效使用不完整的类型"struct dsa_st"
- 标准对此指向成员函数类型模板参数有何说明?是我的代码有误,还是 MSVS 16.6 有问题?
- C++ 类型 * 和类型 *&在函数中的区别是什么
- 两种类型转换有何不同?
- 将QML数组和MAP/对象类型与C 区分开
- 使用临时存储区复制普通的可复制类型:允许吗
- 使用auto声明变量和使用类型名称之间的区别是什么
- 这些数组类型有何不同
- 可调用概念和std::is_function类型特征之间的区别是什么
- c++中这两种类型转换方法的区别是什么?