69901

How to obtain a part of a tuple?

Question:

How can I obtain the tuple type of the first elements in a given tuple type?

If I only ask for one element, it should give me the inner type instead of a tuple type of one element.

In code, how would I get the type I'm looking for?

//TupleType is a tuple of n types 0,1,2,...,n-1 template<size_t i, typename TupleType> struct first_elements { using type = //the "sub-tuple" of types 0,1,2,...,i //exception: if i=0, just the bare type within //the tuple, not the tuple of one element };

Once finished, I could use it like this:

using my_tuple_type = first_elements<1,decltype(great_tuple)>::type; using not_tuple_type = first_elements<0,decltype(great_tuple)>::type;

Answer1:

<strong>UPDATE</strong>

If you have got here seeking code that will <em>extract a specified subsequence of a given std::tuple and/or define the type of a subsequence of a given std::tuple-type</em>, skip to <strong>Anwser to the apparent question</strong>. The OP's question is actually not that one.

<strong>Answer to the actual question</strong>

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 compiletime range-errors. They will barf as std::tuple makes them barf.

(gcc 4.7.2/4.8.1.clang 3.3, -std=c++11)

<strong>Anwser to the apparent question</strong>

#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)

Answer2:

I've almost didn't test, but idea should be OK:

Quite long but straightforward

#include <tuple> #include <iostream> template<int n, typename In, typename... Out> struct first_impl; template<int n, typename First, typename... Other, typename... Out> struct first_impl<n, std::tuple<First, Other...>, Out...> { typedef typename first_impl<n - 1, std::tuple<Other...>, Out..., First>::type type; //move first input to output. }; //need First, Other... here to resolve ambiguity on n = 0 template<typename First, typename... Other, typename... Out> struct first_impl<0, std::tuple<First, Other...>, Out...> { typedef typename std::tuple<Out...> type; //stop if no more elements needed }; //explicit rule for empty tuple because of First, Other... in the previous rule. // actually it's for n = size of tuple template<typename... Out> struct first_impl<0, std::tuple<>, Out...> { typedef typename std::tuple<Out...> type; }; //Simple check int main() { typedef first_impl<2, std::tuple<char, long, int>>::type type; std::cout << std::is_same<type, std::tuple<char, long>>::value; // 1 return 0; }

After that you need to make exception working:

template<int n, typename T> class first_elements<n, T> { typedef typename first_impl<n, T>:: type type; } template<typename First, typename... Other> class first_elements<0, std::tuple<First, Other...>> { typedef First type; } template<> class first_elements<0, std::tuple<>>; // make it incomplete

Answer3:

Use <a href="http://en.cppreference.com/w/cpp/utility/tuple/tuple_element" rel="nofollow">tuple_element</a>:

std::tuple_element<0, TupleType>::type

Together with standard index pack techniques you can use this also to create your subtuples, like std::tuple<typename std::tuple_element<Indices, TupleType>::type...>.

Recommend

  • What is lua_len() alternative in Lua 5.1?
  • Implicit cast from const string to bool [duplicate]
  • C++ String tokenisation from 3D .obj files
  • std::system Exception when instantiating a singleton object
  • Call a macro with parameters : Python win32com API
  • Get the App path without the app name at the end of the app
  • C++ Coin flip program error
  • string.IsNullOrEmpty() Doesn't Seem to Work on a String within a Class within a Class
  • Getting short path in python
  • WPF Template Binding in ToggleButton UserControl
  • How to read piped content in C?
  • Hibernate to update table schema
  • how do i write assembly code from c#?
  • Thread 1: EXC_BAD_ACCESS (code =1 address = 0x0)
  • Memory error in python- how to use more memory
  • Differences in dis-assembled C code of GCC and Borland?
  • C: Incompatible pointer type initializing
  • How to determine if there are bytes available to be read from boost:asio:serial_port
  • Jackson Parser: ignore deserializing for type mismatch
  • Change multiple background-images with jQuery
  • Algorithm for a smudge tool?
  • Display issues when we change from one jquery mobile page to another in firefox
  • Deselecting radio buttons while keeping the View Model in synch
  • AES padding and writing the ciphertext to a disk file
  • Possible to stop flickering java tooltip in heavyweight mode?
  • output of program is not same as passed argument
  • JSON with duplicate key names losing information when parsed
  • Trying to switch camera back to front but getting exception
  • Convert array of 8 bytes to signed long in C++
  • Jquery - Jquery Wysiwyg return html as a string
  • Akka Routing: Reply's send to router ends up as dead letters
  • Linker errors when using intrinsic function via function pointer
  • How get height of the a view with gone visibility and height defined as wrap_content in xml?
  • FormattedException instead of throw new Exception(string.Format(…)) in .NET
  • How to get Windows thread pool to call class member function?
  • LevelDB C iterator
  • unknown Exception android
  • Checking variable from a different class in C#
  • Sorting a 2D array using the second column C++
  • java string with new operator and a literal