如何反转元组类型中元素类型的顺序?

如何反转元组类型中元素类型的顺序?

问题描述:

如何反转元组中的类型?例如,我希望 reverse_tuple< std :: tuple< int,char,bool> :: type std :: tuple< bool ,char,int> 。我尝试了以下操作,但没有成功。我做错了什么?

How do I reverse the types in a tuple? For example, I want reverse_tuple<std::tuple<int, char, bool>>::type to be std::tuple<bool, char, int>. I tried doing the following but it didn't work. What did I do wrong?

#include <type_traits>
#include <tuple>

template <typename... Ts>
struct tuple_reverse;

template <typename T, typename... Ts>
struct tuple_reverse<std::tuple<T, Ts...>>
{
    using type = typename tuple_reverse<
                            std::tuple<
                               typename tuple_reverse<std::tuple<Ts..., T>>::type
                            >
                          >::type;
};

template <typename T>
struct tuple_reverse<std::tuple<T>>
{
    using type = std::tuple<T>;
};

int main()
{
    using result_type = std::tuple<int, bool, char>;
    static_assert(
        std::is_same<
            tuple_reverse<var>::type, std::tuple<char, bool, int>
        >::value, ""
    );
}

这是我的错误:


prog.cpp:实例化'struct tuple_reverse< std :: tuple&lt ; char,int,bool> >:

prog.cpp:15:34:从struct tuple_reverse< std :: tuple< bool,char,int>中递归要求>’$ c>

prog.cpp:15:34:来自struct tuple_reverse< std :: tuple< int,bool,char> >'

prog.cpp:29:31:从此处开始$ c>

prog.cpp:15:34:错误:在'struct tuple_reverse< std :: tuple< int,bool,char>中没有名为'type'的类型>'

prog.cpp:在函数'int main()'中:

prog.cpp:30:9:错误:模板参数1无效


您在这里做错了:

using type = typename tuple_reverse<
                        std::tuple<
                           typename tuple_reverse<std::tuple<Ts..., T>>::type
                        >
                      >::type;

从内而外看,您对元组元素进行了重新排序: tuple&lt ; Ts ...,T> ,然后尝试将其反转,然后将结果放入 tuple ,然后尝试将其反转那个 ...是吗? :)

Looking at it from the inside out, you reorder the tuple elements: tuple<Ts..., T>, then you try to reverse that, then you put the result in a tuple, then you try to reverse that ... huh?! :)

这意味着每次实例化 tuple_reverse 时,都给它一个相同大小的元组,因此永远不会完成,并永久地递归实例化自身。 (然后,如果该递归甚至完成了,则将结果元组类型放入一个元组中,这样您就有一个包含N元元素元组的单元元素元组,并对其进行反转,这无济于事,因为反转单元元组是一个

This means each time you instantiate tuple_reverse you give it a tuple of the same size, so it never finishes, and recursively instantiates itself forever. (Then, if that recursion even finished, you put the resulting tuple type into a tuple, so you have a single-element tuple containing an N-element tuple, and reverse that, which does nothing because reversing a single-element tuple is a no-op.)

您要剥离其中一个元素,然后反转其余元素,然后再次将其连接起来:

You want to peel off one of the elements, then reverse the rest, and concatenate it back again:

using head = std::tuple<T>;
using tail = typename tuple_reverse<std::tuple<Ts...>>::type;

using type = decltype(std::tuple_cat(std::declval<tail>(), std::declval<head>()));

您不需要将其包装在元组中并再次反转:)

And you don't need to wrap it in a tuple and reverse it again :)

您还应该处理空的元组大小写,所以整个事情是:

And you should also handle the empty tuple case, so the whole thing is:

template <typename... Ts>
struct tuple_reverse;

template <>
struct tuple_reverse<std::tuple<>>
{
    using type = std::tuple<>;
};

template <typename T, typename... Ts>
struct tuple_reverse<std::tuple<T, Ts...>>
{
  using head = std::tuple<T>;
  using tail = typename tuple_reverse<std::tuple<Ts...>>::type;

  using type = decltype(std::tuple_cat(std::declval<tail>(), std::declval<head>()));
};

我会做不同的事情。

使用C ++ 14来获取类型

To get just the type, using C++14

template<typename T, size_t... I>
struct tuple_reverse_impl<T, std::index_sequence<I...>>
{
  typedef std::tuple<typename std::tuple_element<sizeof...(I) - 1 - I, T>::type...> type;
};

// partial specialization for handling empty tuples:
template<typename T>
struct tuple_reverse_impl<T, std::index_sequence<>>
{
  typedef T type;
};

template<typename T>
struct tuple_reverse<T>
: tuple_reverse_impl<T, std::make_index_sequence<std::tuple_size<T>::value>>
{ };

或者您可以编写一个函数来反转实际的元组对象,然后使用 decltype(reverse(t))获取类型。要在C ++ 14中反转类似元组的对象:

Or you can write a function to reverse an actual tuple object, then use decltype(reverse(t)) to get the type. To reverse a tuple-like object in C++14:

template<typename T, size_t... I>
auto
reverse_impl(T&& t, std::index_sequence<I...>)
{
  return std::make_tuple(std::get<sizeof...(I) - 1 - I>(std::forward<T>(t))...);
}

template<typename T>
auto
reverse(T&& t)
{
  return reverse_impl(std::forward<T>(t),
                      std::make_index_sequence<std::tuple_size<T>::value>());
}

在C ++ 11中使用 < integer_seq.h> 并添加返回类型和使用 remove_reference 删除元组类型的引用(因为 tuple_size tuple_element 不适用于元组引用):

In C++11 use <integer_seq.h> and add return types and use remove_reference to strip references from the tuple type (because tuple_size and tuple_element don't work with references to tuples):

template<typename T, typename TT = typename std::remove_reference<T>::type, size_t... I>
auto
reverse_impl(T&& t, redi::index_sequence<I...>)
-> std::tuple<typename std::tuple_element<sizeof...(I) - 1 - I, TT>::type...>
{
    return std::make_tuple(std::get<sizeof...(I) - 1 - I>(std::forward<T>(t))...);
}

template<typename T, typename TT = typename std::remove_reference<T>::type>
auto
reverse(T&& t)
-> decltype(reverse_impl(std::forward<T>(t),
                        redi::make_index_sequence<std::tuple_size<TT>::value>()))
{
    return reverse_impl(std::forward<T>(t),
                        redi::make_index_sequence<std::tuple_size<TT>::value>());
}