我认为我们应该包装 stl 的 tuple_element,但你可以:
template <std::size_t, class>
struct nth_of_pack;
template <std::size_t N, template <class...> class Pack, class ... Ts>
struct nth_of_pack <N, Pack<Ts...>>
: std::tuple_element<N, std::tuple<Ts...>> {};
template <std::size_t N, class Pack>
using nth_of_pack_t = typename nth_of_pack<N, Pack>::type;
Demo
更好的解决方案:
tuple_element 似乎总是使用非常慢的递归继承来实现(我已经在 MSVC、gcc、clang 上测试过它们的许多版本——我仍然不知道他们为什么使用递归!)。它也不适用于tuple 以外的任何东西,这很不幸。因此,我们将为任何带有类型参数的类(我称之为“包”)创建一些通用的东西。
下面我们将 Julius 的great answer 用于这个特定问题。有关标准继承、多继承和tuple_element 的性能讨论,请参阅他们的答案。这里我们使用多继承:
#include <utility>
template <class T>
struct tag
{
using type = T;
};
template <class T>
using result_t = typename T::type;
////////////////////////////////////////////////////////////////////////////////
template<std::size_t, std::size_t, class>
struct type_if_equal {};
template<std::size_t n, class T>
struct type_if_equal<n, n, T> : tag<T> {};
////////////////////////////////////////////////////////////////////////////////
template<std::size_t n, class Is, class... Ts>
struct select_nth_implementation;
template<std::size_t n, std::size_t... is, class... Ts>
struct select_nth_implementation<n, std::index_sequence<is...>, Ts...>
: type_if_equal<n, is, Ts>... {};
template<std::size_t n, class... Ts>
struct select_nth : select_nth_implementation<
n, std::index_sequence_for<Ts...>, Ts...> {};
template<std::size_t n, class... Ts>
using select_nth_t = result_t<select_nth<n, Ts...>>;
////////////////////////////////////////////////////////////////////////////////
template <std::size_t, class>
struct nth_of_pack;
template <std::size_t N, template <class...> class Pack, class ... Ts>
struct nth_of_pack <N, Pack<Ts...>> : select_nth<N, Ts...> {};
template <std::size_t N, class Pack>
using nth_of_pack_t = result_t<nth_of_pack<N, Pack>>;
然后我们可以这样使用:
#include <type_traits>
template <class...>
class foo;
int main () {
using my_tuple = foo<int, bool, char, double>;
using second_type = nth_of_pack_t<2, my_tuple>;
static_assert(std::is_same_v<second_type, char>);
}
Demo