对于std :: tuple,如何按类型获取数据,以及如何按索引获取类型?

Joh*_*nes 5 c++11

标题说:给定std :: tuple,我想

  1. 获取给定类型的第一个元素
  2. 获取第i个元素的类型

是否有STL提供的解决方案?还是一个解决方法?有人可以尝试完成我的代码吗?

#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;
}
Run Code Online (Sandbox Code Playgroud)

编译如下:

g++ -std=c++11 -Wall main.cpp -o main
Run Code Online (Sandbox Code Playgroud)

JKo*_*Kor 11

从类型(而不是索引)获取元组的值

从C++ 11开始,没有STL方法来获取类型元组的第一个元素T.
在C++ 14中,应该有一种方法使用新的重载std::get来做你想要的.ISO论文位于N3404N3670.

您可以使用以下命令在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);
}
Run Code Online (Sandbox Code Playgroud)

我在这里托管了Ideone ,但这是我的后代测试功能

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";
}
Run Code Online (Sandbox Code Playgroud)

根据@ Yakk的想法,扩展它以支持类型的多个实例以及在元组中测试的谓词,他提供了下面的代码(也在这里托管在Ideone上)
警告:在C++ 14中新的重载中std::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));
}
Run Code Online (Sandbox Code Playgroud)

获取元组中第n个元素的类型

有一种方法可以获得第n个元素的类型.std::tuple_element<n, decltype(tuple)>::type(感谢@syam)是元组的第n个元素的类型.

  • `decltype(std :: get <n>(tuple))`将产生`T&`或`const T&`,这取决于选择了哪个`std :: get`版本(这又取决于`tuple` constness - 我认为我们可以安全地忽略`T &&`情况,因为它需要抛出`std :: move`).最好使用`std :: tuple_element <n,decltype(tuple)> :: type`来获得"裸"类型的恕我直言. (2认同)