我认为这个实现有 O(log(N)) 实例化深度;对Xeo的 O(log(N)) 索引技巧表示敬意(修改为使用std::size_t
而不是unsigned
)。
编辑:我意识到有一种不同的、更简单且可能更快(编译时间)的解决方案来获得第 n 种类型的元组。
// from https://stackoverflow.com/a/13073076
// indices trick in O(log(N)) instantiations, by Xeo
// using aliases for cleaner syntax
template<class T> using Invoke = typename T::type;
template<std::size_t...> struct seq{ using type = seq; };
template<class S1, class S2> struct concat;
template<std::size_t... I1, std::size_t... I2>
struct concat<seq<I1...>, seq<I2...>>
: seq<I1..., (sizeof...(I1)+I2)...>{};
template<class S1, class S2>
using Concat = Invoke<concat<S1, S2>>;
template<std::size_t N> struct gen_seq;
template<std::size_t N> using GenSeq = Invoke<gen_seq<N>>;
template<std::size_t N>
struct gen_seq : Concat<GenSeq<N/2>, GenSeq<N - N/2>>{};
template<> struct gen_seq<0> : seq<>{};
template<> struct gen_seq<1> : seq<0>{};
/ 的实现类似于std::tuple_element
:
namespace detail
{
template<std::size_t>
struct Any
{
Any(...) {}
};
template<typename T>
struct wrapper { using type = T; };
template<std::size_t... Is>
struct get_nth_helper
{
template<typename T>
static auto deduce(Any<Is>..., wrapper<T>, ...) -> wrapper<T>;
};
template<std::size_t... Is, typename... Ts>
auto deduce_seq(seq<Is...>, wrapper<Ts>... pp)
-> decltype( get_nth_helper<Is...>::deduce(pp...) );
}
#include <tuple>
template<std::size_t n, class Tuple>
struct tuple_element;
template<std::size_t n, class... Ts>
struct tuple_element<n, std::tuple<Ts...>>
{
using wrapped_type = decltype( detail::deduce_seq(gen_seq<n>{},
detail::wrapper<Ts>()...) );
using type = typename wrapped_type::type;
};
使用示例:
#include <typeinfo>
#include <iostream>
int main()
{
std::tuple<int, double, bool, char> t;
tuple_element<1, decltype(t)>::type x;
std::cout << typeid(x).name() << std::endl;
}
感谢@Barry在此答案的早期版本中指出了函数/数组类型的问题,并提供了修复。
原始版本:(注:此版本为简化版,不添加 cv-qualifiers。)
#include <tuple>
namespace detail
{
template < std::size_t Index, class Arg >
struct s_get_one
{
// declare a function that links an Index with an Arg type
friend Arg get(s_get_one, std::integral_constant<std::size_t, Index>);
};
template < typename... Bases >
struct s_get : Bases... {};
}
template < std::size_t I, class T >
struct tuple_element;
template < std::size_t I, class... Args >
struct tuple_element < I, std::tuple<Args...> >
{
template<class T>
struct wrapper { using type = T; };
// deduce indices from seq helper
template < std::size_t... Is >
static auto helper(seq<Is...>)
-> detail::s_get< detail::s_get_one<Is, wrapper<Args>>... >;
// generate indices in O(log(N)) and use name lookup to find the type
using IC = std::integral_constant<std::size_t, I>;
using wrapped_type = decltype( get(helper(gen_seq<sizeof...(Args)>{}), IC{}) );
using type = typename wrapped_type::type;
};