与上次相同的方法,O(logN) 实例化深度。仅使用一个重载,因此它应该消耗更少的资源。
警告:它目前从元组类型中删除引用。
注意:从 中删除了引用pack::declval
。我认为它在每种情况下仍然有效。
Xeo的 O(log(N)) 实例化中的索引技巧;修改为使用std::size_t
而不是unsigned
#include <cstddef>
// 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>{};
今天,我意识到有一种不同的、更简单且可能更快(编译时间)的解决方案来获得第 n 种类型的元组(基本上是 的实现std::tuple_element
)。尽管这是另一个问题的直接解决方案,但为了完整起见,我也会在此处发布。
namespace detail
{
template<std::size_t>
struct Any
{
template<class T> Any(T&&) {}
};
template<typename T>
struct wrapper {};
template<std::size_t... Is>
struct get_nth_helper
{
template<typename T>
static T deduce(Any<Is>..., 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 type = decltype( detail::deduce_seq(gen_seq<n>{},
detail::wrapper<Ts>()...) );
};
最后一个元素的助手:
template<typename Tuple>
struct tuple_last_element;
template<typename... Ts>
struct tuple_last_element<std::tuple<Ts...>>
{
using type = typename tuple_element<sizeof...(Ts)-1,
std::tuple<Ts...>> :: type;
};
使用示例:
#include <iostream>
#include <type_traits>
int main()
{
std::tuple<int, bool, char const&> t{42, true, 'c'};
tuple_last_element<decltype(t)>::type x = 'c'; // it's a reference
static_assert(std::is_same<decltype(x), char const&>{}, "!");
}
原始版本:
#include <tuple>
#include <type_traits>
namespace detail
{
template<typename Seq, typename... TT>
struct get_last_helper;
template<std::size_t... II, typename... TT>
struct get_last_helper< seq<II...>, TT... >
{
template<std::size_t I, std::size_t L, typename T>
struct pack {};
template<typename T, std::size_t L>
struct pack<L, L, T>
{
T declval();
};
// this needs simplification..
template<typename... TTpacked>
struct exp : TTpacked...
{
static auto declval_helper()
-> decltype(std::declval<exp>().declval());
using type = decltype(declval_helper());
};
using type = typename exp<pack<II, sizeof...(TT)-1, TT>...>::type;
};
}
template< typename Tuple >
struct get_last;
template< typename... TT >
struct get_last<std::tuple<TT...>>
{
template<std::size_t... II>
static seq<II...> helper(seq<II...>);
using seq_t = decltype(helper(gen_seq<sizeof...(TT)>()));
using type = typename detail::get_last_helper<seq_t, TT...>::type;
};
int main()
{
using test_type = std::tuple<int, double, bool, char>;
static_assert(std::is_same<char, get_last<test_type>::type>::value, "!");
// fails:
static_assert(std::is_same<int, get_last<test_type>::type>::value, "!");
}