[英]How do I reverse the order of element types in a tuple type?
如何反轉元組中的類型? 例如,我想將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, ""
);
}
這是我的錯誤:
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
你做錯了什么在這里:
using type = typename tuple_reverse<
std::tuple<
typename tuple_reverse<std::tuple<Ts..., T>>::type
>
>::type;
從內到外看,你重新排序元組元素: 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>()));
而且你不需要將它包裝在一個元組中並再次反轉:)
你還應該處理空元組的情況,所以整個事情是:
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
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中反轉類似元組的對象:
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_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>());
}
未經測試。
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;
};
無論如何,那里有些東西。
這也只是顛倒了類型,這似乎是你所追求的。 反轉實際元組將涉及函數,而不是元函數。
我在處理任意類型的反轉模板參數時遇到了這個問題。
Jonathan Wakely的答案適用於元組,但萬一其他人需要反轉任何類型,即T<P1, P2, ..., Pn>
到T<Pn, Pn-1, ..., P1>
,這里是我想出了什么( 從這里采取逆轉邏輯 )。
namespace Details
{
/// Get the base case template type `T<>` of a templated type `T<...>`
template<typename>
struct templated_base_case;
template <template<typename...> class T, typename... TArgs>
struct templated_base_case<T<TArgs...>>
{
using type = T<>;
};
/// Inner reverse logic.
///
/// Reverses the template parameters of a templated type `T` such
/// that `T<A, B, C>` becomes `T<C, B, A>`.
///
/// Note that this requires `T<>` to exist.
template<
typename T,
typename = typename templated_base_case<T>::type>
struct reverse_impl;
template<
template <typename...> class T,
typename... TArgs>
struct reverse_impl<
typename templated_base_case<T<TArgs...>>::type,
T<TArgs...>>
{
using type = T<TArgs...>;
};
template<
template<typename...> class T,
typename first,
typename... rest,
typename... done>
struct reverse_impl<
T<first, rest...>,
T<done...>>
{
using type = typename reverse_impl <T<rest...>, T<first, done...>>::type;
};
/// Swap template parameters of two templated types.
///
/// `L<A, B, C> and R<X, Y, Z>` become `L<X, Y, Z> and R<A, B, C>`.
template<typename L, typename R>
struct swap_template_parameters;
template<
template<typename...> class L,
template<typename...> class R,
typename... x,
typename... y>
struct swap_template_parameters<L<x...>, R<y...>>
{
using left_type = L<y...>;
using right_type = R<x...>;
};
}
/// Parameter pack list of types
template <typename... Args>
struct type_list { };
/// Reverses the arguments of a templates type `T`.
///
/// This uses a `type_list` to allow reversing types like std::pair
/// where `std::pair<>` and `std::pair<T>` are not valid.
template<typename T>
struct reverse_type;
template<template<typename...> class T, typename... TArgs>
struct reverse_type<T<TArgs...>>
{
using type = typename Details::swap_template_parameters<
T<TArgs...>,
typename Details::reverse_impl<type_list<TArgs...>>::type>::left_type;
};
一些實現邏輯可以組合,但我試圖在這里盡可能清楚。
reverse_type
可以應用於元組:
using my_tuple = std::tuple<int, bool, char>;
static_assert(
std::is_same<
typename reverse_type<my_typle>::type,
std::tuple<char, bool, int>>::value,
"");
或其他類型:
/// Standard collections cannot be directly reversed easily
/// because they take default template parameters such as Allocator.
template<typename K, typename V>
struct simple_map : std::unordered_map<K, V> { };
static_assert(
std::is_same<
typename reverse_type<simple_map<std::string, int>>::type,
simple_map<int, std::string>>::value,
"");
稍微詳細解釋一下 。
出於興趣,您是否真的想要反轉元組類型,或者只是以相反的順序處理每個元素(在我的項目中更常見)?
#include <utility>
#include <tuple>
#include <iostream>
namespace detail {
template<class F, class Tuple, std::size_t...Is>
auto invoke_over_tuple(F &&f, Tuple &&tuple, std::index_sequence<Is...>) {
using expand = int[];
void(expand{0,
((f(std::get<Is>(std::forward<Tuple>(tuple)))), 0)...});
}
template<class Sequence, std::size_t I>
struct append;
template<std::size_t I, std::size_t...Is>
struct append<std::index_sequence<Is...>, I> {
using result = std::index_sequence<Is..., I>;
};
template<class Sequence>
struct reverse;
template<>
struct reverse<std::index_sequence<>> {
using type = std::index_sequence<>;
};
template<std::size_t I, std::size_t...Is>
struct reverse<std::index_sequence<I, Is...>> {
using subset = typename reverse<std::index_sequence<Is...>>::type;
using type = typename append<subset, I>::result;
};
}
template<class Sequence>
using reverse = typename detail::reverse<Sequence>::type;
template
<
class Tuple,
class F
>
auto forward_over_tuple(F &&f, Tuple &&tuple) {
using tuple_type = std::decay_t<Tuple>;
constexpr auto size = std::tuple_size<tuple_type>::value;
return detail::invoke_over_tuple(std::forward<F>(f),
std::forward<Tuple>(tuple),
std::make_index_sequence<size>());
};
template
<
class Tuple,
class F
>
auto reverse_over_tuple(F &&f, Tuple &&tuple) {
using tuple_type = std::decay_t<Tuple>;
constexpr auto size = std::tuple_size<tuple_type>::value;
return detail::invoke_over_tuple(std::forward<F>(f),
std::forward<Tuple>(tuple),
reverse<std::make_index_sequence<size>>());
};
int main()
{
auto t = std::make_tuple("1", 2, 3.3, 4.4, 5, 6, "7");
forward_over_tuple([](auto &&x) { std::cout << x << " "; }, t);
std::cout << std::endl;
reverse_over_tuple([](auto &&x) { std::cout << x << " "; }, t);
std::cout << std::endl;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.