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

Me *_*d I 18 c++ tuples variadic-templates c++11

如何反转元组中的类型?例如,我想reverse_tuple<std::tuple<int, char, bool>>::type成为std::tuple<bool, char, int>.我尝试了以下但是没有用.我做错了什么?

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

这是我的错误:

prog.cpp: In instantiation of ‘struct tuple_reverse<std::tuple<char, int, bool> >’:
prog.cpp:15:34: recursively required from ‘struct tuple_reverse<std::tuple<bool, char, int> >’
prog.cpp:15:34: required from ‘struct tuple_reverse<std::tuple<int, bool, char> >’
prog.cpp:29:31: required from here
prog.cpp:15:34: error: no type named ‘type’ in ‘struct tuple_reverse<std::tuple<int, bool, char> >’
prog.cpp: In function ‘int main()’:
prog.cpp:30:9: error: template argument 1 is invalid

Jon*_*ely 20

你做错了什么在这里:

using type = typename tuple_reverse<
                        std::tuple<
                           typename tuple_reverse<std::tuple<Ts..., T>>::type
                        >
                      >::type;
Run Code Online (Sandbox Code Playgroud)

从内到外看,你重新排序元组元素:tuple<Ts..., T>然后你试图扭转它,然后你把结果放在一个tuple,然后你试图扭转那个 ......呵呵?!:)

这意味着每次实例化时tuple_reverse都会给它一个相同大小的元组,因此它永远不会完成,并且会永久地递归实例化它自己.(然后,如果该递归甚至完成,你将结果元组类型放入一个元组中,所以你有一个包含N元素元组的单元素元组,并反转它,这没有任何作用,因为反转单元素元组是一个无操作).

你想剥离其中一个元素,然后反转剩下的元素,然后再将它连接起来:

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

而且你不需要将它包装在一个元组中并再次反转:)

你还应该处理空元组的情况,所以整个事情是:

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

我会做不同的事情.

为了获得类型,使用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>>
{ };
Run Code Online (Sandbox Code Playgroud)

或者您可以编写一个函数来反转实际的元组对象,然后使用它decltype(reverse(t))来获取类型.要在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>());
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 练习,练习,练习。不仅仅是 C++,对于模板元编程,了解一些函数式编程技术也很有用。今天我用 Python 和 OSC 编写一个 Web 应用程序只是为了好玩,因为我正在学习新的东西。 (2认同)

Edw*_*nge 8

未经测试.

template < typename Tuple, typename T >
struct tuple_push;

template < typename T, typename ... Args >
struct tuple_push<std::tuple<Args...>, T>
{
    typedef std::tuple<Args...,T> type;
};

template < typename Tuple >
struct tuple_reverse;

template < typename T, typename ... Args >
struct tuple_reverse<std::tuple<T, Args...>>
{
    typedef typename tuple_push<typename tuple_reverse<std::tuple<Args...>>::type, T>::type type;
};

template < >
struct tuple_reverse<std::tuple<>>
{
    typedef std::tuple<> type;
};
Run Code Online (Sandbox Code Playgroud)

无论如何,那里有些东西.

这也只是颠倒了类型,这似乎是你所追求的.反转实际元组将涉及函数,而不是元函数.