(インデックスではなく) タイプごとにタプルから値を取得する
C++11 の時点で、 type のタプルの最初の要素を取得する STL の方法はありませんT
。
C++14 では、新しいオーバーロードを使用して、必要なことstd::get
を行う方法が必要です。ISO の論文はこちらN3404とこちらN3670にあります。
これは、C++11 で次のように行うことができます。
#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);
}
Ideone hereでホストしていますが、後世のためのテスト機能は次のとおりです
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";
}
これを拡張して、型の複数のインスタンスとタプルでテストする述語をサポートするという @Yakk のアイデアに基づいて、彼は以下のコードを提供しました (ここでもIdeone でホストされています)
警告: C++14 では新しいオーバーロードofstd::get
は、タプルで同じ型の複数のインスタンスを許可しません。代わりに、コンパイル エラーが発生します。さらに、C++14 バージョンは述語もサポートしません。
//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));
}
タプルのn番目の要素の型を取得する
n番目の要素の型を取得する方法があります。std::tuple_element<n, decltype(tuple)>::type
(thanks @syam) は、タプルの n 番目の要素の型です。