For std :: tuple, how to get data by type and how to get type by index?

The name reads: given std :: tuple, I would like

  • get the first element of a given type
  • get the type of the i-th element

Is there a solution provided by STL ? Or a workaround ? Can someone try to execute my code?

#include <tuple> int main () { std::tuple<int,char,int> mytuple (10,'a', 5); // how to get the first int element here? (10) // int x = std::get_me_the_first<int>(mytuple); // how to get the type of the second element here? // std::get_me_type_of<1> ch = 'x'; return 0; } 

Compiled as follows:

 g++ -std=c++11 -Wall main.cpp -o main 
+5
source share
2 answers

Getting value from a tuple by type (instead of index)

As in C ++ 11, there is no STL way to get the first element of a tuple of type T
In C ++ 14, there should be a way to use the new std::get overload to do what you want. The ISO paper is here N3404 and here N3670 .

You can do this in C ++ 11 with the following:

 #include<tuple> #include<type_traits> #include<string> #include<iostream> template<int Index, class Search, class First, class... Types> struct get_internal { typedef typename get_internal<Index + 1, Search, Types...>::type type; static constexpr int index = Index; }; template<int Index, class Search, class... Types> struct get_internal<Index, Search, Search, Types...> { typedef get_internal type; static constexpr int index = Index; }; template<class T, class... Types> T get(std::tuple<Types...> tuple) { return std::get<get_internal<0,T,Types...>::type::index>(tuple); } 

I have it posted on Ideone here , but here is my test function for posterity

 int main() { std::tuple<int, double, std::string> test{1, 1.7, "test"}; std::cout<<"get<0> == get<int> :"<< (std::get<0>(test) == get<int>(test))<< "\n"; std::cout<<"get<1> == get<double> :"<<(std::get<1>(test) == get<double>(test))<< "\n"; std::cout<<"get<2> == get<std::string> :"<<(std::get<2>(test) == get<std::string>(test))<< "\n"; } 

Based on @Yakk's idea of ​​extending this to support multiple instances of a type, as well as a predicate for testing in a tuple, he provided the code below (also posted on Ideone here )
Be warned: in C ++ 14, the new overload of std::get does not allow multiple instances of the same type in a tuple. Instead, a compilation error occurs. In addition, C ++ 14 will also not support predicates.

 //Include same headers as before template<bool b, typename T=void> using EnableIf = typename std::enable_if<b,T>::type; template<int Index, template<typename T>class Search, int Which, typename, class First, class... Types> struct get_internal: get_internal<Index + 1, Search, Which, void, Types...> {}; template<int Index, template<typename T>class Search, int Which, class First, class... Types> struct get_internal<Index, Search, Which, EnableIf<!Search<First>::value>, First, Types...>: get_internal<Index + 1, Search, Which, void, Types...> {}; template<int Index, template<typename T>class Search, int Which, class First, class... Types> struct get_internal<Index, Search, Which, EnableIf<Search<First>::value>, First, Types...>: get_internal<Index + 1, Search, Which-1, void, Types...> {}; template<int Index, template<typename T>class Search, class First, class... Types> struct get_internal<Index, Search, 0, EnableIf<Search<First>::value>, First, Types...>: std::integral_constant<int, Index> {}; template<template<typename>class Test, int Which=0, class... Types> auto get(std::tuple<Types...>& tuple)-> decltype(std::get<get_internal<0,Test,Which,void,Types...>::value>(tuple)) { return std::get<get_internal<0,Test,Which,void,Types...>::value>(tuple); } template<template<typename>class Test, int Which=0, class... Types> auto get(std::tuple<Types...> const& tuple)-> decltype(std::get<get_internal<0,Test,Which,void,Types...>::value>(tuple)) { return std::get<get_internal<0,Test,Which,void,Types...>::value>(tuple); } template<template<typename>class Test, int Which=0, class... Types> auto get(std::tuple<Types...>&& tuple)-> decltype(std::move(std::get<get_internal<0,Test,Which,void,Types...>::value>(tuple))) { return std::move(std::get<get_internal<0,Test,Which,void,Types...>::value>(tuple)); } template<typename T> struct is_type { template<typename U> using test = std::is_same<T,U>; }; template<class T, int Which=0, class... Types> T& get(std::tuple<Types...>& tuple) { return get<is_type<T>::template test,Which>(tuple); } template<class T, int Which=0, class... Types> T const& get(std::tuple<Types...> const& tuple) { return get<is_type<T>::template test,Which>(tuple); } template<class T, int Which=0, class... Types> T&& get(std::tuple<Types...>&& tuple) { return std::move(get<is_type<T>::template test,Which>(tuple)); } 

Getting the type of the nth element in a tuple

There is a way to get the type of the nth element. std::tuple_element<n, decltype(tuple)>::type (thanks @syam) is the type of the nth element of the tuple.

+10
source

Just for a giggle, not what you want, and very limited in the sense that you need to add new types, and it works in the reverse order, but here is getNthTypeReverse , which only supports the types int and char haha http: / /ideone.com/Uk2JTC

 #include <tuple> #include <iostream> using namespace std; typedef std::tuple<int,char,int> TupleType; template<typename TupleT,typename OnElementHandler, size_t N> struct TupleIterator{ static void call(const TupleT& tuple, OnElementHandler& OnElement){ auto nthElem = std::get<N>(tuple); OnElement(nthElem); TupleIterator<TupleT,OnElementHandler,N-1>::call(tuple,OnElement); } }; template<typename TupleT,typename OnElementHandler> struct TupleIterator<TupleT,OnElementHandler,0>{ static void call(const TupleT& tuple, OnElementHandler& OnElement){ auto firstElem = std::get<0>(tuple); OnElement(firstElem); } }; template<typename T1,typename T2> struct IsSame{enum{result = 0};}; template<typename T> struct IsSame<T,T>{ enum{result = 1}; }; template<typename T,size_t TargetCount, size_t BeginIndex, size_t EndIndex, typename Tuple> T getNthTypeReverse(const Tuple& t, const T& defaultValue = T()){ //assert 0 <= N <= tuple.size T result = defaultValue; struct NthGrabber{ T& result; const size_t n; size_t count; NthGrabber(T& r, const size_t n): result(r),n(n),count(0){} void operator()(const int i){ if(IsSame<T,int>::result){ ++count; if(count == n) result = i; } } void operator()(const char c){ if(IsSame<T,char>::result){ ++count; if(count == n) result = c; } } //overload for other version too... }OnElement(result,TargetCount+1); //WILL update result if condition meet const size_t tupleSize = EndIndex - BeginIndex; TupleIterator<TupleType,NthGrabber,tupleSize>::call(t,OnElement); return result; } int main(){ TupleType t(10,'a',5); const size_t tupleSize = std::tuple_size<decltype(t)>::value - 1; int lastInt = getNthTypeReverse<int,0,0,tupleSize,TupleType>(t,-1); int secondLastInt = getNthTypeReverse<int,1,0,tupleSize,TupleType>(t,-1); int thirdLastInt = getNthTypeReverse<int,2,0,tupleSize,TupleType>(t,-1); cout << "lastInt = " << lastInt << endl; cout << "SecondLast = " << secondLastInt << endl; cout << "ThirdLast = " << thirdLastInt << endl; char lastChar = getNthTypeReverse<char,0,0,tupleSize,TupleType>(t,'\0'); cout << "LastChar = " << lastChar << endl; return 0; } 

output:

 lastInt = 5 SecondLast = 10 ThirdLast = -1 LastChar = a 
+1
source

Source: https://habr.com/ru/post/959464/


All Articles