[英]get part of std::tuple
I have a tuple of unknown size (it's template parametr of method)我有一个未知大小的元组(它是方法的模板参数)
Is it way to get part of it (I need throw away first element of it)有没有办法得到它的一部分(我需要扔掉它的第一个元素)
For example, I have tuple<int,int,int>(7,12,42)
.例如,我有
tuple<int,int,int>(7,12,42)
。 I want tuple<int,int>(12,42)
here我想要
tuple<int,int>(12,42)
这里
With help of a compile-time integer list:在编译时整数列表的帮助下:
#include <cstdlib>
template <size_t... n>
struct ct_integers_list {
template <size_t m>
struct push_back
{
typedef ct_integers_list<n..., m> type;
};
};
template <size_t max>
struct ct_iota_1
{
typedef typename ct_iota_1<max-1>::type::template push_back<max>::type type;
};
template <>
struct ct_iota_1<0>
{
typedef ct_integers_list<> type;
};
We could construct the tail simply by parameter-pack expansion:我们可以简单地通过参数包扩展来构造尾部:
#include <tuple>
template <size_t... indices, typename Tuple>
auto tuple_subset(const Tuple& tpl, ct_integers_list<indices...>)
-> decltype(std::make_tuple(std::get<indices>(tpl)...))
{
return std::make_tuple(std::get<indices>(tpl)...);
// this means:
// make_tuple(get<indices[0]>(tpl), get<indices[1]>(tpl), ...)
}
template <typename Head, typename... Tail>
std::tuple<Tail...> tuple_tail(const std::tuple<Head, Tail...>& tpl)
{
return tuple_subset(tpl, typename ct_iota_1<sizeof...(Tail)>::type());
// this means:
// tuple_subset<1, 2, 3, ..., sizeof...(Tail)-1>(tpl, ..)
}
Usage:用法:
#include <cstdio>
int main()
{
auto a = std::make_tuple(1, "hello", 7.9);
auto b = tuple_tail(a);
const char* s = nullptr;
double d = 0.0;
std::tie(s, d) = b;
printf("%s %g\n", s, d);
// prints: hello 7.9
return 0;
}
(On ideone: http://ideone.com/Tzv7v ; the code works in g++ 4.5 to 4.7 and clang++ 3.0) (关于 ideone: http ://ideone.com/Tzv7v ;代码在 g++ 4.5 到 4.7 和 clang++ 3.0 中工作)
There may be an easier way, but this is a start.可能有更简单的方法,但这是一个开始。 The "tail" function template returns a copied tuple with all values of the original except the first.
“tail”函数模板返回一个复制的元组,其中包含除第一个之外的所有原始值。 This compiles with GCC 4.6.2 in C++0x-mode.
这在 C++0x 模式下使用 GCC 4.6.2 编译。
template<size_t I>
struct assign {
template<class ResultTuple, class SrcTuple>
static void x(ResultTuple& t, const SrcTuple& tup) {
std::get<I - 1>(t) = std::get<I>(tup);
assign<I - 1>::x(t, tup);
}
};
template<>
struct assign<1> {
template<class ResultTuple, class SrcTuple>
static void x(ResultTuple& t, const SrcTuple& tup) {
std::get<0>(t) = std::get<1>(tup);
}
};
template<class Tup> struct tail_helper;
template<class Head, class... Tail>
struct tail_helper<std::tuple<Head, Tail...>> {
typedef typename std::tuple<Tail...> type;
static type tail(const std::tuple<Head, Tail...>& tup) {
type t;
assign<std::tuple_size<type>::value>::x(t, tup);
return t;
}
};
template<class Tup>
typename tail_helper<Tup>::type tail(const Tup& tup) {
return tail_helper<Tup>::tail(tup);
}
With C++17, you can use std::apply
:使用 C++17,您可以使用
std::apply
:
template <typename Head, typename... Tail>
std::tuple<Tail...> tuple_tail(const std::tuple<Head, Tail...>& t)
{
return apply([](auto head, auto... tail) {
return std::make_tuple(tail...)};
}, t);
}
A tuple slice operation (that also works for std::array
and std::pair
) can be defined like this (C++14 required):元组切片操作(也适用于
std::array
和std::pair
)可以这样定义(需要 C++14):
namespace detail
{
template <std::size_t Ofst, class Tuple, std::size_t... I>
constexpr auto slice_impl(Tuple&& t, std::index_sequence<I...>)
{
return std::forward_as_tuple(
std::get<I + Ofst>(std::forward<Tuple>(t))...);
}
}
template <std::size_t I1, std::size_t I2, class Cont>
constexpr auto tuple_slice(Cont&& t)
{
static_assert(I2 >= I1, "invalid slice");
static_assert(std::tuple_size<std::decay_t<Cont>>::value >= I2,
"slice index out of bounds");
return detail::slice_impl<I1>(std::forward<Cont>(t),
std::make_index_sequence<I2 - I1>{});
}
And an arbitrary subset of a tuple t
can be obtained like so :可以像这样获得元组
t
的任意子集:
tuple_slice<I1, I2>(t);
Where [I1, I2)
is the exclusive range of the subset and the return value is a tuple of either references or values depending on whether the input tuple is an lvalue or an rvalue respectively (a thorough elaboration can be found in myblog ).其中
[I1, I2)
是子集的唯一范围,返回值是引用或值的元组,具体取决于输入元组是左值还是右值(详细说明可以在我的博客中找到)。
I made some modifications to Adam's code that would strip off the first N arguments of the tuple, as well as create a new tuple with only the last N types ... Here is the complete code (note: if anyone decides to +1 my answer, also please +1 Adam's answer since that is what this code is based on, and I don't wish to take any credit away from his contribution) :我对Adam 的代码做了一些修改,去掉了元组的前 N 个参数,并创建了一个只有最后 N 个类型的新元组......这是完整的代码(注意:如果有人决定 +1 我的回答,也请 +1 Adam 的回答,因为这是此代码的基础,我不想从他的贡献中获得任何功劳) :
//create a struct that allows us to create a new tupe-type with the first
//N types truncated from the front
template<size_t N, typename Tuple_Type>
struct tuple_trunc {};
template<size_t N, typename Head, typename... Tail>
struct tuple_trunc<N, std::tuple<Head, Tail...>>
{
typedef typename tuple_trunc<N-1, std::tuple<Tail...>>::type type;
};
template<typename Head, typename... Tail>
struct tuple_trunc<0, std::tuple<Head, Tail...>>
{
typedef std::tuple<Head, Tail...> type;
};
/*-------Begin Adam's Code-----------
Note the code has been slightly modified ... I didn't see the need for the extra
variadic templates in the "assign" structure. Hopefully this doesn't break something
I didn't forsee
*/
template<size_t N, size_t I>
struct assign
{
template<class ResultTuple, class SrcTuple>
static void x(ResultTuple& t, const SrcTuple& tup)
{
std::get<I - N>(t) = std::get<I>(tup);
assign<N, I - 1>::x(t, tup); //this offsets the assignment index by N
}
};
template<size_t N>
struct assign<N, 1>
{
template<class ResultTuple, class SrcTuple>
static void x(ResultTuple& t, const SrcTuple& tup)
{
std::get<0>(t) = std::get<1>(tup);
}
};
template<size_t TruncSize, class Tup> struct th2;
//modifications to this class change "type" to the new truncated tuple type
//as well as modifying the template arguments to assign
template<size_t TruncSize, class Head, class... Tail>
struct th2<TruncSize, std::tuple<Head, Tail...>>
{
typedef typename tuple_trunc<TruncSize, std::tuple<Head, Tail...>>::type type;
static type tail(const std::tuple<Head, Tail...>& tup)
{
type t;
assign<TruncSize, std::tuple_size<type>::value>::x(t, tup);
return t;
}
};
template<size_t TruncSize, class Tup>
typename th2<TruncSize, Tup>::type tail(const Tup& tup)
{
return th2<TruncSize, Tup>::tail(tup);
}
//a small example
int main()
{
std::tuple<double, double, int, double> test(1, 2, 3, 4);
tuple_trunc<2, std::tuple<double, double, int, double>>::type c = tail<2>(test);
return 0;
}
Please don't use!请不要使用!
int
but may fail for your type!).int
但可能不适用于您的类型!)。 See comments for discussion.见评论讨论。 I'm leaving this answer just for reference.
我留下这个答案仅供参考。
Even simpler:更简单:
tuple<int,int,int> origin{7,12,42};
tuple<int, int> &tail1 = (tuple<int, int>&)origin;
tuple<int> &tail2 = (tuple<int>&)origin;
cout << "tail1: {" << get<0>(tail1) << ", " << get<1>(tail1) << "}" << endl;
cout << "tail2: {" << get<0>(tail2) << "}" << endl;
I got:我有:
tail1: {12, 42}
tail2: {42}
I'm not certain that this is not an unspecified behaviour.我不确定这不是未指明的行为。 Works for me: Fedora 20 and
对我有用:Fedora 20 和
❯ clang --version
clang version 3.3 (tags/RELEASE_33/final)
Target: x86_64-redhat-linux-gnu
Thread model: posix
❯ gcc --version
gcc (GCC) 4.8.2 20131212 (Red Hat 4.8.2-7)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
References: article on voidnish.wordpress.com/ .参考资料: 关于 voidnish.wordpress.com/ 的文章。
The c++17 way: C++17 方式:
#include <tuple>
#include <string>
template <size_t __begin, size_t...__indices, typename Tuple>
auto tuple_slice_impl(Tuple &&tuple, std::index_sequence<__indices...>) {
return std::make_tuple(std::get<__begin + __indices>(std::forward<Tuple>(tuple))...);
}
template <size_t __begin, size_t __count, typename Tuple>
auto tuple_slice(Tuple &&tuple) {
static_assert(__count > 0, "splicing tuple to 0-length is weird...");
return tuple_slice_impl<__begin>(std::forward<Tuple>(tuple), std::make_index_sequence<__count>());
}
template <size_t __begin, size_t __count, typename Tuple>
using tuple_slice_t = decltype(tuple_slice<__begin, __count>(Tuple{}));
using test_tuple = std::tuple<int, int, bool, nullptr_t, std::string>;
using sliced_test = tuple_slice_t<2, 2, test_tuple>;
static_assert(std::tuple_size_v<sliced_test> == 2);
static_assert(std::is_same_v<std::decay_t<decltype(std::get<0>(sliced_test{}))>, bool>);
static_assert(std::is_same_v<std::decay_t<decltype(std::get<1>(sliced_test{}))>, nullptr_t>);
#include <cassert>
int main() {
test_tuple tuple {
-1, 42, true, nullptr, "hello"
};
auto spliced = tuple_slice<3, 2>(tuple);
assert(std::get<0>(spliced) == nullptr);
assert(std::get<1>(spliced) == std::get<4>(tuple));
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.