更新
如果您在这里寻找将提取给定子序列的指定子序列std::tuple
和/或定义给定类型的子序列的std::tuple
类型的代码,请跳到Anwser 到明显的问题。OP的问题实际上不是那个问题。
回答实际问题
这将做:
#include <cstddef>
#include <type_traits>
#include <tuple>
template<size_t I, typename TupleType, typename Enable = void>
struct first_elements;
template<size_t I, typename TupleType>
struct first_elements<I,TupleType,typename std::enable_if<(I == 0)>::type>
{
using type = typename std::tuple_element<0,TupleType>::type;
};
template<size_t I, typename TupleType>
struct first_elements<I,TupleType,typename std::enable_if<(I == 1)>::type>
{
using type =
typename std::tuple<typename std::tuple_element<0,TupleType>::type>;
};
template<size_t I, typename TupleType>
struct first_elements<I,TupleType,typename std::enable_if<(I > 1)>::type>
{
using next =
typename std::tuple<typename std::tuple_element<I - 1,TupleType>::type>;
using prev = typename first_elements<I - 1,TupleType>::type;
using type = decltype(
std::tuple_cat(std::declval<prev>(),std::declval<next>())
);
};
// A test program...
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
auto tup = std::tuple<char,int,float,double>();
cout <<
std::is_same<first_elements<0,decltype(tup)>::type,char>::value << endl;
cout <<
std::is_same<first_elements<1,decltype(tup)>::type,std::tuple<char>>::value
<< endl;
cout <<
std::is_same<
first_elements<2,decltype(tup)>::type,
std::tuple<char,int>>::value
<< endl;
cout <<
std::is_same<
first_elements<3,decltype(tup)>::type,
std::tuple<char,int,float>>::value
<< endl;
cout <<
std::is_same<
first_elements<4,decltype(tup)>::type,
std::tuple<char,int,float,double>>::value
<< endl;
return 0;
}
没有针对编译时范围错误的特殊预防措施。他们会呕吐,就像
std::tuple
让他们呕吐一样。
(gcc 4.7.2/4.8.1.clang 3.3, -std=c++11
)
对明显问题的回答
#include <type_traits>
#include <tuple>
/* A class template to obtain the type and value of the
the subsequence [First,Last) of a tuple type TupleType
First:- The start of the subsequence [First,Last)
Last:- The end of the subsequence [First,Last)
TupleType: - The std::tuple type to be queried.
Enable:- SFINAE parameter
The public member `type` is defined as the type of the
subsequence [First,Last) of `TupleType`.
The static member function:
`type get(TupleType const & tup)`
returns the `std::tuple` of the subsequence [First,Last) of `tup`.
`std::tuple<>` is returned when `First`
is out of range. The terminal sub-tuple indexed by `First` is
returned if only `Last` is out of range.
*/
template<
unsigned First, unsigned Last, typename TupleType, typename Enable = void
>
struct tuple_part;
template<unsigned First, unsigned Last, typename TupleType>
struct tuple_part<
First,Last,TupleType,
typename std::enable_if<
(First >= Last || First >= std::tuple_size<TupleType>::value)
>::type
>
{
using type = std::tuple<>;
static constexpr type get(TupleType const & tup) {
return type();
}
};
template<unsigned First, unsigned Last, typename TupleType>
struct tuple_part<
First,Last,TupleType,
typename std::enable_if<
(Last == First + 1 && First < std::tuple_size<TupleType>::value)
>::type
>
{
using type =
typename std::tuple<typename std::tuple_element<First,TupleType>::type>;
static constexpr type get(TupleType const & tup) {
return type(std::get<First>(tup));
}
};
template<unsigned First, unsigned Last, typename TupleType>
struct tuple_part<
First,Last,TupleType,
typename std::enable_if<
(Last > First + 1 && Last <= std::tuple_size<TupleType>::value)
>::type
>
{
using head = typename tuple_part<First,First + 1,TupleType>::type;
using tail = typename tuple_part<First + 1,Last,TupleType>::type;
using type = decltype(
std::tuple_cat(std::declval<head>(),std::declval<tail>())
);
static constexpr type get(TupleType const & tup) {
return std::tuple_cat(
tuple_part<First,First + 1,TupleType>::get(tup),
tuple_part<First + 1,Last,TupleType>::get(tup)
);
}
};
template<unsigned First, unsigned Last, typename TupleType>
struct tuple_part<
First,Last,TupleType,
typename std::enable_if<
(Last > First + 1 && Last > std::tuple_size<TupleType>::value)
>::type
> : tuple_part<First,std::tuple_size<TupleType>::value,TupleType>
{
using base_type =
tuple_part<First,std::tuple_size<TupleType>::value,TupleType>;
using type = typename base_type::type;
};
/*
`get_part<First,Last>(TupleType const & tup)`
returns the `std::tuple` of the subsequence [First,Last) of `tup`
*/
template<unsigned First, unsigned Last, typename TupleType>
constexpr
decltype(
tuple_part<First,Last,TupleType>::get(std::declval<TupleType>())
)
get_part(TupleType const & tup)
{
return tuple_part<First,Last,TupleType>::get(tup);
}
/*
`get_part<First>(TupleType const & tup)`
returns the `std::tuple` of the terminal subsequence of `tup`
indexed by `First`
*/
template<unsigned First, typename TupleType>
constexpr
decltype(
get_part<First,std::tuple_size<TupleType>::value>(std::declval<TupleType>())
)
get_part(TupleType const & tup)
{
return get_part<First,std::tuple_size<TupleType>::value>(tup);
}
// A test program...
#include <cassert>
int main(int argc, char **argv)
{
using type = std::tuple<char,int,float,double>;
constexpr type t0(1,2,3.0,4.0);
constexpr auto p0 = get_part<0,1>(t0);
assert(p0 == std::tuple<char>(1));
auto p1 = get_part<0,2>(t0);
assert((p1 == std::tuple<char,int>(1,2)));
auto p2 = get_part<0,3>(t0);
assert((p2 == std::tuple<char,int,float>(1,2,3.0)));
auto p3 = get_part<0>(t0);
assert((p3 == std::tuple<char,int,float,double>(1,2,3.0,4.0)));
auto p4 = get_part<1,2>(t0);
assert(p4 == std::tuple<int>(2));
auto p5 = get_part<1,3>(t0);
assert((p5 == std::tuple<int,float>(2,3.0)));
auto p6 = get_part<1>(t0);
assert((p6 == std::tuple<int,float,double>(2,3.0,4.0)));
auto p7 = get_part<2,3>(t0);
assert(p7 == std::tuple<float>(3.0));
auto p8 = get_part<2,4>(t0);
assert((p8 == std::tuple<float,double>(3.0,4.0)));
auto p9 = get_part<3>(t0);
assert(p9 == std::tuple<double>(4.0));
auto p10 = get_part<3,5>(t0);
assert(p10 == std::tuple<double>(4.0));
auto p11 = get_part<4,4>(t0);
assert(p11 == std::tuple<>());
auto p12 = get_part<5,4>(t0);
assert(p12 == std::tuple<>());
return 0;
}
// EOF
(gcc 4.7.2/4.8.1,clang 3.2/3.3, -std=c++11
)