如何展平嵌套模板参数?
how to flatten nested templates parameters?
说我有
template<class ... T> pack { };
我要转换
pack<int, pack<int, pack<int, pack<int>>>>
进入
pack<int, int, int, int>
我该怎么做?
基于std::tuple_cat
的可能的快速实现:
template <class T>
struct tuple_flatten {
using type = std::tuple<T>;
};
template <class... Args>
struct tuple_flatten<pack<Args...>> {
using type = decltype(std::tuple_cat(
typename tuple_flatten<Args>::type{}...));
};
template <class T>
struct tuple_to_pack;
template <class... Args>
struct tuple_to_pack<std::tuple<Args...>> {
using type = pack<Args...>;
};
template <class T>
struct flatten {
using type = typename tuple_to_pack<
typename tuple_flatten<T>::type>::type;
};
template <class T>
using flatten_t = typename flatten<T>::type;
我会递归地解压和打包东西:
template<class Head, class... Packed>
struct repack
{
using type = Head;
};
template<class Head, class... Packed>
struct repack<pack<Head, pack<Packed...>>>
{
using type = pack<Head, repack<Packed...>>;
};
类型 repack<pack<int, pack<int, pack<int, pack<int>>>>>::type
转换为:
pack<int, repack<pack<int, pack<int, pack<int>>>>>
pack<int, int, repack<pack<int, pack<int>>>>
pack<int, int, int, repack<pack<int>>>
pack<int, int, int, int>
我提出以下结构并使用
template <typename T0, typename...>
struct flatt_helper
{ using type = T0; };
template <typename ... Ts1, typename T0, typename ... Ts2>
struct flatt_helper<pack<Ts1...>, T0, Ts2...>
: flatt_helper<pack<Ts1..., T0>, Ts2...>
{ };
template <typename ... Ts1, template <typename ...> class C,
typename ... Ts2, typename ... Ts3>
struct flatt_helper<pack<Ts1...>, C<Ts2...>, Ts3...>
: flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
{ };
template <typename T>
using flatt = typename flatt_helper<pack<>, T>::type;
通过这种方式,您可以将 pack
和其他模板-模板展平,如 std::tuple
,以及更复杂的示例(例如 Holt 建议的 pack<int, pack<int, int>, int>
)。
如果你只想扁平化 pack
,避免所有模板都扁平化......,我的意思是......如果你想要那个
pack<int, pack<int, std::tuple<int, long>>>
被压平为
pack<int, int, std::tuple<int, long>>
而不是
pack<int, int, int, long>
你必须在最后一个 flatt_helper
专业化中删除模板模板参数并简化如下
template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
struct flatt_helper<pack<Ts1...>, pack<Ts2...>, Ts3...>
: flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
{ };
下面是一个完整的编译示例(完全扁平化)
#include <tuple>
#include <type_traits>
template <typename...>
struct pack
{ };
template <typename T0, typename...>
struct flatt_helper
{ using type = T0; };
template <typename ... Ts1, typename T0, typename ... Ts2>
struct flatt_helper<pack<Ts1...>, T0, Ts2...>
: flatt_helper<pack<Ts1..., T0>, Ts2...>
{ };
template <typename ... Ts1, template <typename ...> class C,
typename ... Ts2, typename ... Ts3>
struct flatt_helper<pack<Ts1...>, C<Ts2...>, Ts3...>
: flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
{ };
template <typename T>
using flatt = typename flatt_helper<pack<>, T>::type;
int main()
{
using T0 = pack<int, pack<int, pack<int, pack<int>>>>;
using T1 = pack<int, int, int, int>;
using T2 = flatt<T0>;
using T3 = pack<int, pack<int, long>, std::tuple<pack<int, char>, long>>;
using T4 = pack<int, int, long, int, char, long>;
using T5 = flatt<T3>;
static_assert( std::is_same<T1, T2>::value, "!" );
static_assert( std::is_same<T4, T5>::value, "!" );
}
pack_cat
采用一系列包装或非包装,并将任何包装在一起,加上非包装的物品。
template<class T0, class...Ts>
struct catter;
template<class...Ts>
using pack_cat = typename catter<Ts...>::type;
template<class T0>
struct catter<T0>{ using type=T0; };
template<class...Ts, class...Us, class...Vs>
struct catter<pack<Ts...>, pack<Us...>, Vs...>{ using type=pack_cat<pack<Ts...,Us...>,Vs...>; };
template<class...Ts, class U, class...Vs>
struct catter<pack<Ts...>, U, Vs...>{ using type=pack_cat<pack<Ts...,U>,Vs...>; };
unpacker
获取一个包,并递归地解包所有子包并将它们连接起来。
template<class X>
struct unpacker{using type=X;};
template<class X>
using unpack=typename unpacker<X>::type;
template<class...Ts>
struct unpacker<pack<Ts...>>{using type=pack_cat<pack<>,unpack<Ts>...>;};
测试一下:
pack<int,int,int,int>{}=unpack<pack<int,pack<int,pack<int,pack<int>>>>>{};
pack<int,int,int>{} = unpack<pack<int,int,int>>{};
pack<int,int,int>{} = unpack<pack<pack<int,int>,int>>{};
哪个编译IFF这两个类型是一样的
template< typename >
struct is_tuple: false_type{};
template<typename ... input_t>
struct is_tuple< std::tuple<input_t ... > > :
true_type{};
template<typename ... input_t> using flat_tuple= decltype(std::tuple_cat( std::declval< std::conditional_t< is_tuple< input_t >::value, input_t, std::tuple< input_t > > >()... ) );
现在...完全不同的东西...(好吧...不完全...几乎是 Holt 的解决方案,但使用函数而不是结构)
您可以将 std::tuple_cat()
与 decltype()
组合在几个已声明的函数中,以在 std::tuple
中平放 pack
template <typename T>
constexpr std::tuple<T> foo (T);
template <typename ... Ts>
constexpr auto foo (pack<Ts...>)
-> decltype( std::tuple_cat(foo(std::declval<Ts>())...) );
和另一个声明的函数在 pack
中再次转换扁平化的 std::tuple
template <typename ... Ts>
constexpr pack<Ts...> bar (std::tuple<Ts...>);
现在您可以按如下方式在拼合器中组合
template <typename T>
using fl = decltype(bar(foo(std::declval<T>())));
下面是一个完整的编译示例
#include <tuple>
#include <type_traits>
template <typename...>
struct pack
{ };
template <typename T>
constexpr std::tuple<T> foo (T);
template <typename ... Ts>
constexpr auto foo (pack<Ts...>)
-> decltype( std::tuple_cat(foo(std::declval<Ts>())...) );
template <typename ... Ts>
constexpr pack<Ts...> bar (std::tuple<Ts...>);
template <typename T>
using fl = decltype(bar(foo(std::declval<T>())));
int main()
{
using U0 = pack<int, pack<int, pack<int, pack<int>>>>;
using U1 = pack<int, int, int, int>;
using U2 = fl<U0>;
using U3 = pack<int, pack<int, long>, pack<pack<int, char>, long>>;
using U4 = pack<int, int, long, int, char, long>;
using U5 = fl<U3>;
static_assert( std::is_same<U1, U2>::value, "!" );
static_assert( std::is_same<U4, U5>::value, "!" );
}
派对迟到了?
template <class... Ts> struct flatten;
template <class... Ts> struct flatten<pack<Ts...>, pack<>>
{
using type = pack<Ts...>;
};
template <class... Ts> struct flatten<pack<Ts...>>
: flatten<pack<>, pack<Ts...>>
{ };
template <class... Ts, class T, class... Rs>
struct flatten<pack<Ts...>, pack<T, Rs...>> : flatten<pack<Ts...>, T, pack<Rs...>>
{ };
template <class... Ts, class T, class... Es>
struct flatten<pack<Ts...>, T, pack<Es...>> : flatten<pack<Ts..., T>, pack<Es...>>
{ };
template <class... Ts, class... Rs, class... Es>
struct flatten<pack<Ts...>, pack<Rs...>, pack<Es...>> : flatten<pack<Ts...>, pack<Rs..., Es...>>
{ };
template <class T> using flatten_t = typename flatten<T>::type;
using T1 = pack<int, pack<int, int>, pack<int, int>, int>;
using T2 = pack<int, pack<int, pack<int, pack<int, int>>>, int>;
using R1 = pack<int,int,int,int,int,int>;
static_assert(std::is_same_v<R1, flatten_t<T1>>);
static_assert(std::is_same_v<R1, flatten_t<T2>>);
说我有
template<class ... T> pack { };
我要转换
pack<int, pack<int, pack<int, pack<int>>>>
进入
pack<int, int, int, int>
我该怎么做?
基于std::tuple_cat
的可能的快速实现:
template <class T>
struct tuple_flatten {
using type = std::tuple<T>;
};
template <class... Args>
struct tuple_flatten<pack<Args...>> {
using type = decltype(std::tuple_cat(
typename tuple_flatten<Args>::type{}...));
};
template <class T>
struct tuple_to_pack;
template <class... Args>
struct tuple_to_pack<std::tuple<Args...>> {
using type = pack<Args...>;
};
template <class T>
struct flatten {
using type = typename tuple_to_pack<
typename tuple_flatten<T>::type>::type;
};
template <class T>
using flatten_t = typename flatten<T>::type;
我会递归地解压和打包东西:
template<class Head, class... Packed>
struct repack
{
using type = Head;
};
template<class Head, class... Packed>
struct repack<pack<Head, pack<Packed...>>>
{
using type = pack<Head, repack<Packed...>>;
};
类型 repack<pack<int, pack<int, pack<int, pack<int>>>>>::type
转换为:
pack<int, repack<pack<int, pack<int, pack<int>>>>>
pack<int, int, repack<pack<int, pack<int>>>>
pack<int, int, int, repack<pack<int>>>
pack<int, int, int, int>
我提出以下结构并使用
template <typename T0, typename...>
struct flatt_helper
{ using type = T0; };
template <typename ... Ts1, typename T0, typename ... Ts2>
struct flatt_helper<pack<Ts1...>, T0, Ts2...>
: flatt_helper<pack<Ts1..., T0>, Ts2...>
{ };
template <typename ... Ts1, template <typename ...> class C,
typename ... Ts2, typename ... Ts3>
struct flatt_helper<pack<Ts1...>, C<Ts2...>, Ts3...>
: flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
{ };
template <typename T>
using flatt = typename flatt_helper<pack<>, T>::type;
通过这种方式,您可以将 pack
和其他模板-模板展平,如 std::tuple
,以及更复杂的示例(例如 Holt 建议的 pack<int, pack<int, int>, int>
)。
如果你只想扁平化 pack
,避免所有模板都扁平化......,我的意思是......如果你想要那个
pack<int, pack<int, std::tuple<int, long>>>
被压平为
pack<int, int, std::tuple<int, long>>
而不是
pack<int, int, int, long>
你必须在最后一个 flatt_helper
专业化中删除模板模板参数并简化如下
template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
struct flatt_helper<pack<Ts1...>, pack<Ts2...>, Ts3...>
: flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
{ };
下面是一个完整的编译示例(完全扁平化)
#include <tuple>
#include <type_traits>
template <typename...>
struct pack
{ };
template <typename T0, typename...>
struct flatt_helper
{ using type = T0; };
template <typename ... Ts1, typename T0, typename ... Ts2>
struct flatt_helper<pack<Ts1...>, T0, Ts2...>
: flatt_helper<pack<Ts1..., T0>, Ts2...>
{ };
template <typename ... Ts1, template <typename ...> class C,
typename ... Ts2, typename ... Ts3>
struct flatt_helper<pack<Ts1...>, C<Ts2...>, Ts3...>
: flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
{ };
template <typename T>
using flatt = typename flatt_helper<pack<>, T>::type;
int main()
{
using T0 = pack<int, pack<int, pack<int, pack<int>>>>;
using T1 = pack<int, int, int, int>;
using T2 = flatt<T0>;
using T3 = pack<int, pack<int, long>, std::tuple<pack<int, char>, long>>;
using T4 = pack<int, int, long, int, char, long>;
using T5 = flatt<T3>;
static_assert( std::is_same<T1, T2>::value, "!" );
static_assert( std::is_same<T4, T5>::value, "!" );
}
pack_cat
采用一系列包装或非包装,并将任何包装在一起,加上非包装的物品。
template<class T0, class...Ts>
struct catter;
template<class...Ts>
using pack_cat = typename catter<Ts...>::type;
template<class T0>
struct catter<T0>{ using type=T0; };
template<class...Ts, class...Us, class...Vs>
struct catter<pack<Ts...>, pack<Us...>, Vs...>{ using type=pack_cat<pack<Ts...,Us...>,Vs...>; };
template<class...Ts, class U, class...Vs>
struct catter<pack<Ts...>, U, Vs...>{ using type=pack_cat<pack<Ts...,U>,Vs...>; };
unpacker
获取一个包,并递归地解包所有子包并将它们连接起来。
template<class X>
struct unpacker{using type=X;};
template<class X>
using unpack=typename unpacker<X>::type;
template<class...Ts>
struct unpacker<pack<Ts...>>{using type=pack_cat<pack<>,unpack<Ts>...>;};
测试一下:
pack<int,int,int,int>{}=unpack<pack<int,pack<int,pack<int,pack<int>>>>>{};
pack<int,int,int>{} = unpack<pack<int,int,int>>{};
pack<int,int,int>{} = unpack<pack<pack<int,int>,int>>{};
哪个编译IFF这两个类型是一样的
template< typename >
struct is_tuple: false_type{};
template<typename ... input_t>
struct is_tuple< std::tuple<input_t ... > > :
true_type{};
template<typename ... input_t> using flat_tuple= decltype(std::tuple_cat( std::declval< std::conditional_t< is_tuple< input_t >::value, input_t, std::tuple< input_t > > >()... ) );
现在...完全不同的东西...(好吧...不完全...几乎是 Holt 的解决方案,但使用函数而不是结构)
您可以将 std::tuple_cat()
与 decltype()
组合在几个已声明的函数中,以在 std::tuple
pack
template <typename T>
constexpr std::tuple<T> foo (T);
template <typename ... Ts>
constexpr auto foo (pack<Ts...>)
-> decltype( std::tuple_cat(foo(std::declval<Ts>())...) );
和另一个声明的函数在 pack
std::tuple
template <typename ... Ts>
constexpr pack<Ts...> bar (std::tuple<Ts...>);
现在您可以按如下方式在拼合器中组合
template <typename T>
using fl = decltype(bar(foo(std::declval<T>())));
下面是一个完整的编译示例
#include <tuple>
#include <type_traits>
template <typename...>
struct pack
{ };
template <typename T>
constexpr std::tuple<T> foo (T);
template <typename ... Ts>
constexpr auto foo (pack<Ts...>)
-> decltype( std::tuple_cat(foo(std::declval<Ts>())...) );
template <typename ... Ts>
constexpr pack<Ts...> bar (std::tuple<Ts...>);
template <typename T>
using fl = decltype(bar(foo(std::declval<T>())));
int main()
{
using U0 = pack<int, pack<int, pack<int, pack<int>>>>;
using U1 = pack<int, int, int, int>;
using U2 = fl<U0>;
using U3 = pack<int, pack<int, long>, pack<pack<int, char>, long>>;
using U4 = pack<int, int, long, int, char, long>;
using U5 = fl<U3>;
static_assert( std::is_same<U1, U2>::value, "!" );
static_assert( std::is_same<U4, U5>::value, "!" );
}
派对迟到了?
template <class... Ts> struct flatten;
template <class... Ts> struct flatten<pack<Ts...>, pack<>>
{
using type = pack<Ts...>;
};
template <class... Ts> struct flatten<pack<Ts...>>
: flatten<pack<>, pack<Ts...>>
{ };
template <class... Ts, class T, class... Rs>
struct flatten<pack<Ts...>, pack<T, Rs...>> : flatten<pack<Ts...>, T, pack<Rs...>>
{ };
template <class... Ts, class T, class... Es>
struct flatten<pack<Ts...>, T, pack<Es...>> : flatten<pack<Ts..., T>, pack<Es...>>
{ };
template <class... Ts, class... Rs, class... Es>
struct flatten<pack<Ts...>, pack<Rs...>, pack<Es...>> : flatten<pack<Ts...>, pack<Rs..., Es...>>
{ };
template <class T> using flatten_t = typename flatten<T>::type;
using T1 = pack<int, pack<int, int>, pack<int, int>, int>;
using T2 = pack<int, pack<int, pack<int, pack<int, int>>>, int>;
using R1 = pack<int,int,int,int,int,int>;
static_assert(std::is_same_v<R1, flatten_t<T1>>);
static_assert(std::is_same_v<R1, flatten_t<T2>>);