Get index of a tuple element's type?
template <class T, class Tuple>
struct Index;
template <class T, class... Types>
struct Index<T, std::tuple<T, Types...>> {
static const std::size_t value = 0;
};
template <class T, class U, class... Types>
struct Index<T, std::tuple<U, Types...>> {
static const std::size_t value = 1 + Index<T, std::tuple<Types...>>::value;
};
See it live at Coliru.
This implementation returns the index of the first occurrence of a given type. Asking for the index of a type that is not in the tuple results in a compile error (and a fairly ugly one at that).
How to get an element of type list by index
I want to avoid using tuples as type lists for use cases, that require
instantiation for passing a list likef(L{})
If you don't want to instanciate std::tuple
but you're ok with it in
unevaluated contexts, you may take advantage of std::tuple_element
to
implement your typeAt
trait:
template <std::size_t I, typename T>
struct typeAt;
template <std::size_t I, typename... Args>
struct typeAt<I, type_list<Args...>> : std::tuple_element<I, std::tuple<Args...>> {};
// ^ let library authors do the work for you
using L = type_list<int, char, float, double>;
using T = typename typeAt<2, L>::type;
static_assert(std::is_same<T, float>::value, "");
How to extract all tuple elements of given type(s) into new tuple
Only C++17 is needed here.
std::tuple_cat
is one of my favorite tools.
Use a
std::index_sequence
to chew through the tupleUse a specialization to pick up either a
std::tuple<>
or astd::tuple<T>
out of the original tuple, for each indexed element.Use
std::tuple_cat
to glue everything together.The only tricky part is checking if each tuple element is wanted. To do that, put all the wanted types into its own
std::tuple
, and use a helper class for that part, too.
#include <utility>
#include <tuple>
#include <iostream>
// Answer one simple question: here's a type, and a tuple. Tell me
// if the type is one of the tuples types. If so, I want it.
template<typename wanted_type, typename T> struct is_wanted_type;
template<typename wanted_type, typename ...Types>
struct is_wanted_type<wanted_type, std::tuple<Types...>> {
static constexpr bool wanted=(std::is_same_v<wanted_type, Types>
|| ...);
};
// Ok, the ith index in the tuple, here's its std::tuple_element type.
// And wanted_element_t is a tuple of all types we want to extract.
//
// Based on which way the wind blows we'll produce either a std::tuple<>
// or a std::tuple<tuple_element_t>.
template<size_t i, typename tuple_element_t,
typename wanted_element_t,
bool wanted=is_wanted_type<tuple_element_t, wanted_element_t>::wanted>
struct extract_type {
template<typename tuple_type>
static auto do_extract_type(const tuple_type &t)
{
return std::tuple<>{};
}
};
template<size_t i, typename tuple_element_t, typename wanted_element_t>
struct extract_type<i, tuple_element_t, wanted_element_t, true> {
template<typename tuple_type>
static auto do_extract_type(const tuple_type &t)
{
return std::tuple<tuple_element_t>{std::get<i>(t)};
}
};
// And now, a simple fold expression to pull out all wanted types
// and tuple-cat them together.
template<typename wanted_element_t, typename tuple_type, size_t ...i>
auto get_type_t(const tuple_type &t, std::index_sequence<i...>)
{
return std::tuple_cat( extract_type<i,
typename std::tuple_element<i, tuple_type>::type,
wanted_element_t>::do_extract_type(t)... );
}
template<typename ...wanted_element_t, typename ...types>
auto get_type(const std::tuple<types...> &t)
{
return get_type_t<std::tuple<wanted_element_t...>>(
t, std::make_index_sequence<sizeof...(types)>());
}
int main()
{
std::tuple<int, const char *, double> t{1, "alpha", 2.5};
std::tuple<double, int> u=get_type<int, double>(t);
std::cout << std::get<0>(u) << " " << std::get<1>(u) << std::endl;
std::tuple<int, int, int, char, char, char, double, double, float> tt;
auto uu=get_type<float, double>(tt);
static_assert(std::is_same_v<decltype(uu),
std::tuple<double, double, float>>);
return 0;
}
How to get the position of a tuple element
UPDATE:
I eventually figured out a way to achieve this in a simpler way that also uses short-circuiting (and therefore performs less comparisons).
Given some machinery:
namespace detail
{
template<int I, int N, typename T, typename... Args>
struct find_index
{
static int call(std::tuple<Args...> const& t, T&& val)
{
return (std::get<I>(t) == val) ? I :
find_index<I + 1, N, T, Args...>::call(t, std::forward<T>(val));
}
};
template<int N, typename T, typename... Args>
struct find_index<N, N, T, Args...>
{
static int call(std::tuple<Args...> const& t, T&& val)
{
return (std::get<N>(t) == val) ? N : -1;
}
};
}
The function that clients are going to invoke eventually boils down to this simple trampoline:
template<typename T, typename... Args>
int find_index(std::tuple<Args...> const& t, T&& val)
{
return detail::find_index<sizeof...(Args), T, Args...>::
call(t, std::forward<T>(val));
}
Finally, this is how you would use it in your program:
#include <iostream>
int main()
{
std::tuple<int, int, int, int> a(2, 3, 1, 4);
std::cout << find_index(a, 1) << std::endl; // Prints 2
std::cout << find_index(a, 2) << std::endl; // Prints 0
std::cout << find_index(a, 5) << std::endl; // Prints -1 (not found)
}
And here is a live example.
EDIT:
If you want to perform the search backwards, you can replace the above machinery and the trampoline function with the following versions:
#include <tuple>
#include <algorithm>
namespace detail
{
template<int I, typename T, typename... Args>
struct find_index
{
static int call(std::tuple<Args...> const& t, T&& val)
{
return (std::get<I - 1>(t) == val) ? I - 1 :
find_index<I - 1, T, Args...>::call(t, std::forward<T>(val));
}
};
template<typename T, typename... Args>
struct find_index<0, T, Args...>
{
static int call(std::tuple<Args...> const& t, T&& val)
{
return (std::get<0>(t) == val) ? 0 : -1;
}
};
}
template<typename T, typename... Args>
int find_index(std::tuple<Args...> const& t, T&& val)
{
return detail::find_index<0, sizeof...(Args) - 1, T, Args...>::
call(t, std::forward<T>(val));
}
Here is a live example.
ORIGINAL ANSWER:
This does not really sound like a typical way one would use tuples, but if you really want to do this, then here is a way (works with tuples of any size).
First, some machinery (the well-known indices trick):
template <int... Is>
struct index_list { };
namespace detail
{
template <int MIN, int N, int... Is>
struct range_builder;
template <int MIN, int... Is>
struct range_builder<MIN, MIN, Is...>
{
typedef index_list<Is...> type;
};
template <int MIN, int N, int... Is>
struct range_builder : public range_builder<MIN, N - 1, N - 1, Is...>
{ };
}
template<int MIN, int MAX>
using index_range = typename detail::range_builder<MIN, MAX>::type;
Then, a couple of overloaded function templates:
#include <tuple>
#include <algorithm>
template<typename T, typename... Args, int... Is>
int find_index(std::tuple<Args...> const& t, T&& val, index_list<Is...>)
{
auto l = {(std::get<Is>(t) == val)...};
auto i = std::find(begin(l), end(l), true);
if (i == end(l)) { return -1; }
else { return i - begin(l); }
}
template<typename T, typename... Args>
int find_index(std::tuple<Args...> const& t, T&& val)
{
return find_index(t, std::forward<T>(val),
index_range<0, sizeof...(Args)>());
}
And here is how you would use it:
#include <iostream>
int main()
{
std::tuple<int, int, int, int> a(2, 3, 1, 4);
std::cout << find_index(a, 1) << std::endl; // Prints 2
std::cout << find_index(a, 2) << std::endl; // Prints 0
std::cout << find_index(a, 5) << std::endl; // Prints -1 (not found)
}
And here is a live example.
How to get the index of an element in a tuple via address?
Something you do not need in C++14, a mini indexes library:
template<unsigned...>struct indexes{using type=indexes;};
template<unsigned Cnt,unsigned...Is>
struct make_indexes:make_indexes<Cnt-1,Cnt-1,Is...>{};
template<unsigned...Is>
struct make_indexes<0,Is...>:indexes<Is...>{};
template<unsigned Cnt>
using make_indexes_t=typename make_indexes<Cnt>::type;
Function that does actual work. Creates an array pointers-to-elements. Then searches for p
. The nullptr
and -1
make it work for empty tuples.
template<unsigned...Is,class Tuple>
unsigned index_of(indexes<Is...>,void const* p, Tuple const&t){
void const* r[]={ nullptr, &std::get<Is>(t)... };
auto it = std::find( std::begin(r), std::end(r), p );
if (it==std::end(r))
return -1;
else
return (it-std::begin(r))-1;
}
you can put that in a details
namespace.
The final function:
template<class...Ts>
unsigned index_of( void const*p, std::tuple<Ts...> const& t ){
return index_of( make_indexes_t<sizeof...(Ts)>{}, p, t );
}
return unsigned(-1)
on failure.
Get a tuple element in runtime
The example codes can be rewritten. Since multiple return types are not possible in C++, so that you will have to get it via a lambda function passed as an argument. The same approach was also mentioned by the guy in the comment
#include <tuple>
#include <utility>
#include <type_traits>
#include <stdexcept>
template<
typename Tuple,
typename F,
typename Indices=std::make_index_sequence<std::tuple_size<Tuple>::value>>
struct runtime_get_func_table;
template<typename Tuple, typename F, size_t I>
void applyForIndex(Tuple& t, F f) {
f(std::get<I>(t));
}
template<typename Tuple, typename F, size_t ... Indices>
struct runtime_get_func_table<Tuple,F,std::index_sequence<Indices...>>{
using FuncType = void(*)(Tuple&, F);
static constexpr FuncType table[]={
&applyForIndex<Tuple, F, Indices>...
};
};
template<typename Tuple, typename F>
void runtime_get(Tuple& t,size_t index, F f) {
using tuple_type=typename std::remove_reference<Tuple>::type;
if(index>=std::tuple_size<tuple_type>::value)
throw std::runtime_error("Out of range");
runtime_get_func_table<tuple_type, F>::table[index](t, f);
}
int main() {
std::tuple<int ,char, float> t(10, 's', 10.2);
runtime_get(t, 0, [] (auto& v) {
// Do something v = get<0>(t);
});
}
How to get N-th type from a tuple?
You can use a class template and partial specializations to do what you want. (Note that std::tuple_element
does almost the same like the other answer says):
#include <tuple>
#include <type_traits>
template <int N, typename... Ts>
struct get;
template <int N, typename T, typename... Ts>
struct get<N, std::tuple<T, Ts...>>
{
using type = typename get<N - 1, std::tuple<Ts...>>::type;
};
template <typename T, typename... Ts>
struct get<0, std::tuple<T, Ts...>>
{
using type = T;
};
int main()
{
using var = std::tuple<int, bool, std::string>;
using type = get<2, var>::type;
static_assert(std::is_same<type, std::string>::value, ""); // works
}
For std::tuple, how to get data by type, and how to get type by index?
Getting value from tuple by type (instead of index)
As of 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 using a new overload of std::get
to do what you want. The ISO paper is located 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 hosted on Ideone here, but here's 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 of @Yakk's idea of extending this to support multiple instances of a type as well as a predicate to test for in the tuple, he provided the code below (also hosted on Ideone here)
Be warned: in C++14 the new overload of std::get
does not allow multiple instances of the same type in the tuple. It instead issues a compile error. In addition the C++14 version will not support predicates either.
//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 type of n-th element in tuple
There is a way to get the type of the n-th element. std::tuple_element<n, decltype(tuple)>::type
(thanks @syam) is the type of the n-th element of the tuple.
Finding the max element's index in a Tuple list? (Python)
If you want only max tuple value:
max_tuple = max(temp_tuple, key=lambda x:x[1])
print(max_tuple)
>> ('B', 3)
if you want index of max tuple too:
max_tuple = max(temp_tuple, key=lambda x:x[1])
max_tuple_index = temp_tuple.index(max_tuple)
print(max_tuple)
print(max_tuple_index)
>> ('B', 3)
>> 1
Related Topics
C++ - Decimal to Binary Converting
Vector::At VS. Vector::Operator[]
Defining Global Constant in C++
Polymorphic_Allocator: When and Why Should I Use It
Lambda Capture as Const Reference
Osx - Replace Gcc Version 4.2.1 with 4.9 Installed via Homebrew
How to Solve the Error Lnk2019: Unresolved External Symbol - Function
How to Output the Value of an Enum Class in C++11
Why How to Use 'Std::Move' on a 'Const' Object
How to Find All the Functions Exposed by a Dll
Expansion with Variadic Templates
Is C++11's Long Long Really at Least 64 Bits
Why Is There No Reallocation Functionality in C++ Allocators