如何区分模板化存储的类型class
How to distinguish the type stored in a templated class
假设我有一个 class 假装是其模板包中的类型之一,我如何才能获得函数中一个模板参数所在的索引或当前索引的类型指向?
template<typename... Vs>
struct TypeIndex {
int index_of_type;
void some_function() {
cout << static_cast<get_type_from_index()> (some_member);
}
};
我知道这里需要一些 class 专业化,但我不能完全理解如何在代码中实现它。任何帮助都会很棒,谢谢!
下面的 class 正在使用您其他问题的答案中的代码。我没有包含它,因为依赖它的析构函数调度尚未实现。
像这样使用它:using my_type = pack_type_at<index, Vs...>::type;
,其中 index
是一个在编译时可用的整数,就像来自模板参数一样。
投票前请注意:这仅适用于编译时索引,因此不能完全回答问题。在其他地方我说任务是 "nontrivial" 因为需要使用 运行 时间索引以某种方式找到和 运行 对应于包索引之一的适当函数重载。
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;
};
get the index at which one template parameter is at in a function
有两百万种方法可以做到这一点。这是一个:
// 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...> {};
which type the current index points to
索引的值仅在运行时已知,而 C++ 是静态类型的,因此这是不可能的。
对于编译时索引来说,这是微不足道的:
template<size_t I, class... Ts>
using at = std::tuple_element_t<I, std::tuple<Ts...>>;
But then how does boost::variant
do this with the apply_visitor
function?
apply_visitor
的想法是将其编译成类似 switch
的结构:
// pseudocode
switch(index) {
case 0:
return visitor(get<0>(variant));
break;
case 1:
return visitor(get<1>(variant));
break;
// etc.
};
请注意,visitor
需要与变体中的 每个 类型一起使用,并且 return 在每种情况下都使用相同的类型,这就是以上工作。
当然,如果类型的可能数量是无限的(在 C++03 中 - 没有可变参数模板 - boost::variant
显然有一个上限,那么实际上你不能写 switch
关于它可以处理的类型数量,因此他们可以根据需要直接编写 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);
}
有更有效的方法(例如,进行二进制搜索,或使用跳转 table)。
假设我有一个 class 假装是其模板包中的类型之一,我如何才能获得函数中一个模板参数所在的索引或当前索引的类型指向?
template<typename... Vs>
struct TypeIndex {
int index_of_type;
void some_function() {
cout << static_cast<get_type_from_index()> (some_member);
}
};
我知道这里需要一些 class 专业化,但我不能完全理解如何在代码中实现它。任何帮助都会很棒,谢谢!
下面的 class 正在使用您其他问题的答案中的代码。我没有包含它,因为依赖它的析构函数调度尚未实现。
像这样使用它:using my_type = pack_type_at<index, Vs...>::type;
,其中 index
是一个在编译时可用的整数,就像来自模板参数一样。
投票前请注意:这仅适用于编译时索引,因此不能完全回答问题。在其他地方我说任务是 "nontrivial" 因为需要使用 运行 时间索引以某种方式找到和 运行 对应于包索引之一的适当函数重载。
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;
};
get the index at which one template parameter is at in a function
有两百万种方法可以做到这一点。这是一个:
// 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...> {};
which type the current index points to
索引的值仅在运行时已知,而 C++ 是静态类型的,因此这是不可能的。
对于编译时索引来说,这是微不足道的:
template<size_t I, class... Ts>
using at = std::tuple_element_t<I, std::tuple<Ts...>>;
But then how does
boost::variant
do this with theapply_visitor
function?
apply_visitor
的想法是将其编译成类似 switch
的结构:
// pseudocode
switch(index) {
case 0:
return visitor(get<0>(variant));
break;
case 1:
return visitor(get<1>(variant));
break;
// etc.
};
请注意,visitor
需要与变体中的 每个 类型一起使用,并且 return 在每种情况下都使用相同的类型,这就是以上工作。
当然,如果类型的可能数量是无限的(在 C++03 中 - 没有可变参数模板 - boost::variant
显然有一个上限,那么实际上你不能写 switch
关于它可以处理的类型数量,因此他们可以根据需要直接编写 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);
}
有更有效的方法(例如,进行二进制搜索,或使用跳转 table)。