UPDATE
If you have search code that selects the specified subsequence of the given std::tuple
and / or determines the type of subsequence of the given type std::tuple
, go to Anwser to the obvious question . The OP question is actually not the same.
The answer to the actual question
This will do:
#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; }
No special precautions for command range errors. They will be std::tuple
makes them barf.
(gcc 4.7.2 / 4.8.1.clang 3.3, -std=c++11
)
Answer the obvious question
#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
)