C++ 从std::tuple开始创建子元组
让我们假设给定了一个std::tuple。我想创建一个新的std::tuple,其类型是[0,sizeof…some_types-2]中索引的类型。例如,假设起始元组是std::tuple。我想获得定义为std::tuple的子元组 我对可变模板很陌生。作为第一步,我尝试编写一个负责存储原始std::tuple的不同类型的结构,目的是创建一个与std::tuple new_tuple中的类型相同的新元组 我想做的是:C++ 从std::tuple开始创建子元组,c++,templates,c++11,variadic-templates,stdtuple,C++,Templates,C++11,Variadic Templates,Stdtuple,让我们假设给定了一个std::tuple。我想创建一个新的std::tuple,其类型是[0,sizeof…some_types-2]中索引的类型。例如,假设起始元组是std::tuple。我想获得定义为std::tuple的子元组 我对可变模板很陌生。作为第一步,我尝试编写一个负责存储原始std::tuple的不同类型的结构,目的是创建一个与std::tuple new_tuple中的类型相同的新元组 我想做的是: std::tuple<type_list<bool, double
std::tuple<type_list<bool, double, int>::type...> new_tuple // this won't work
下一步是丢弃参数包中的最后一个元素。如何访问类型列表中存储的多个类型?如何丢弃其中的一些
谢谢。一种方法是递归地将两个元组传递给helper结构,该结构接受源元组的第一个元素,并将其添加到另一个元组的末尾:
#include <iostream>
#include <tuple>
#include <type_traits>
namespace detail {
template<typename...>
struct truncate;
// this specialization does the majority of the work
template<typename... Head, typename T, typename... Tail>
struct truncate< std::tuple<Head...>, std::tuple<T, Tail...> > {
typedef typename
truncate< std::tuple<Head..., T>, std::tuple<Tail...> >::type type;
};
// this one stops the recursion when there's only
// one element left in the source tuple
template<typename... Head, typename T>
struct truncate< std::tuple<Head...>, std::tuple<T> > {
typedef std::tuple<Head...> type;
};
}
template<typename...>
struct tuple_truncate;
template<typename... Args>
struct tuple_truncate<std::tuple<Args...>> {
// initiate the recursion - we start with an empty tuple,
// with the source tuple on the right
typedef typename detail::truncate< std::tuple<>, std::tuple<Args...> >::type type;
};
int main()
{
typedef typename tuple_truncate< std::tuple<bool, double, int> >::type X;
// test
std::cout << std::is_same<X, std::tuple<bool, double>>::value; // 1, yay
}
.使用索引序列技术,这种操作相当容易:生成一个索引序列,比元组少两个索引,并使用该序列从原始字段中选择字段。从C++14使用和返回类型推断:
template <typename... T, std::size_t... I>
auto subtuple_(const std::tuple<T...>& t, std::index_sequence<I...>) {
return std::make_tuple(std::get<I>(t)...);
}
template <int Trim, typename... T>
auto subtuple(const std::tuple<T...>& t) {
return subtuple_(t, std::make_index_sequence<sizeof...(T) - Trim>());
}
在C++11中:
#include <cstddef> // for std::size_t
template<typename T, T... I>
struct integer_sequence {
using value_type = T;
static constexpr std::size_t size() noexcept {
return sizeof...(I);
}
};
namespace integer_sequence_detail {
template <typename, typename> struct concat;
template <typename T, T... A, T... B>
struct concat<integer_sequence<T, A...>, integer_sequence<T, B...>> {
typedef integer_sequence<T, A..., B...> type;
};
template <typename T, int First, int Count>
struct build_helper {
using type = typename concat<
typename build_helper<T, First, Count/2>::type,
typename build_helper<T, First + Count/2, Count - Count/2>::type
>::type;
};
template <typename T, int First>
struct build_helper<T, First, 1> {
using type = integer_sequence<T, T(First)>;
};
template <typename T, int First>
struct build_helper<T, First, 0> {
using type = integer_sequence<T>;
};
template <typename T, T N>
using builder = typename build_helper<T, 0, N>::type;
} // namespace integer_sequence_detail
template <typename T, T N>
using make_integer_sequence = integer_sequence_detail::builder<T, N>;
template <std::size_t... I>
using index_sequence = integer_sequence<std::size_t, I...>;
template<size_t N>
using make_index_sequence = make_integer_sequence<size_t, N>;
#include <tuple>
template <typename... T, std::size_t... I>
auto subtuple_(const std::tuple<T...>& t, index_sequence<I...>)
-> decltype(std::make_tuple(std::get<I>(t)...))
{
return std::make_tuple(std::get<I>(t)...);
}
template <int Trim, typename... T>
auto subtuple(const std::tuple<T...>& t)
-> decltype(subtuple_(t, make_index_sequence<sizeof...(T) - Trim>()))
{
return subtuple_(t, make_index_sequence<sizeof...(T) - Trim>());
}
.这里有一种直接解决问题的方法
template<unsigned...s> struct seq { typedef seq<s...> type; };
template<unsigned max, unsigned... s> struct make_seq:make_seq<max-1, max-1, s...> {};
template<unsigned...s> struct make_seq<0, s...>:seq<s...> {};
template<unsigned... s, typename Tuple>
auto extract_tuple( seq<s...>, Tuple& tup ) {
return std::make_tuple( std::get<s>(tup)... );
}
这为您提供了一种将type_列表的类型累积到任意参数包保存模板中的方法。但您的问题不需要这样做。具有边界检查的元组的子范围,无需声明帮助器类:
template <size_t starting, size_t elems, class tuple, class seq = decltype(std::make_index_sequence<elems>())>
struct sub_range;
template <size_t starting, size_t elems, class ... args, size_t ... indx>
struct sub_range<starting, elems, std::tuple<args...>, std::index_sequence<indx...>>
{
static_assert(elems <= sizeof...(args) - starting, "sub range is out of bounds!");
using tuple = std::tuple<std::tuple_element_t<indx + starting, std::tuple<args...>> ...>;
};
用法:
struct a0;
...
struct a8;
using range_outer = std::tuple<a0, a1, a2, a3, a4, a5, a6, a7, a8>;
sub_range<2, 3, range_outer>::tuple; //std::tuple<a2, a3, a4>
您的意思是[0,sizeof…某些_类型-2]的可能重复,即您的示例中的[0,1]?是的,已更正。谢谢,比你早两分钟@凯西矿只有一半的长度。。。如果包含符合C++14的整数_序列的副本;OHH,我在MaxySeq中有指数递归,这很好,对吗?FWWW,我认为log n索引对于简单的Script片段来说太麻烦了,所以对于清晰简洁的版本,+1到YAKK。P@Yakk我很喜欢你的抽取元组的泛型。泛型是一个词吗?我该睡觉了。@Yakk现在我休息得更好了,请允许我注意,1我甚至没有注意到我的双entendre是Yakk之前长度的一半,不小于,2在执行extract\u tuple时忘记了扩展s。固定的
template<template<typename...>class target>
struct gather {
typedef typename type_list<types...>::template gather<target>::type parent_result;
typedef typename append< parent_result, T >::type type;
};
template <size_t starting, size_t elems, class tuple, class seq = decltype(std::make_index_sequence<elems>())>
struct sub_range;
template <size_t starting, size_t elems, class ... args, size_t ... indx>
struct sub_range<starting, elems, std::tuple<args...>, std::index_sequence<indx...>>
{
static_assert(elems <= sizeof...(args) - starting, "sub range is out of bounds!");
using tuple = std::tuple<std::tuple_element_t<indx + starting, std::tuple<args...>> ...>;
};
struct a0;
...
struct a8;
using range_outer = std::tuple<a0, a1, a2, a3, a4, a5, a6, a7, a8>;
sub_range<2, 3, range_outer>::tuple; //std::tuple<a2, a3, a4>