获取一个模板参数在函数中的索引
有两百万种方法可以做到这一点。这是一个:
// 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 需要与变体中的 每个 类型一起使用,并且在每种情况下都返回相同的类型,这就是上述工作的原因。
当然,实际上,如果可能的类型数量是无限的(在 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);
}
有更有效的方法(例如,进行二分查找或使用跳转表)。