how to flatten nested templates parameters?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
Say I have
template<class ... T> pack { };
I want to convert
pack<int, pack<int, pack<int, pack<int>>>>
into
pack<int, int, int, int>
How can I do so?
c++ templates variadic-templates
add a comment |
Say I have
template<class ... T> pack { };
I want to convert
pack<int, pack<int, pack<int, pack<int>>>>
into
pack<int, int, int, int>
How can I do so?
c++ templates variadic-templates
2
Do you also want to convert stuff likepack<int, pack<int, int>, int>
?
– Holt
Jan 3 at 16:02
add a comment |
Say I have
template<class ... T> pack { };
I want to convert
pack<int, pack<int, pack<int, pack<int>>>>
into
pack<int, int, int, int>
How can I do so?
c++ templates variadic-templates
Say I have
template<class ... T> pack { };
I want to convert
pack<int, pack<int, pack<int, pack<int>>>>
into
pack<int, int, int, int>
How can I do so?
c++ templates variadic-templates
c++ templates variadic-templates
edited Jan 3 at 16:04


NathanOliver
98.8k16138218
98.8k16138218
asked Jan 3 at 16:01
Apliex-DdrApliex-Ddr
1468
1468
2
Do you also want to convert stuff likepack<int, pack<int, int>, int>
?
– Holt
Jan 3 at 16:02
add a comment |
2
Do you also want to convert stuff likepack<int, pack<int, int>, int>
?
– Holt
Jan 3 at 16:02
2
2
Do you also want to convert stuff like
pack<int, pack<int, int>, int>
?– Holt
Jan 3 at 16:02
Do you also want to convert stuff like
pack<int, pack<int, int>, int>
?– Holt
Jan 3 at 16:02
add a comment |
7 Answers
7
active
oldest
votes
I propose the following struct and using
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;
This way you can flatten pack
and other template-template, as std::tuple
, and also more complex examples (the pack<int, pack<int, int>, int>
suggested by Holt, by example).
If you want flat only pack
, avoiding that all template-template are flattened..., I mean... if you want that
pack<int, pack<int, std::tuple<int, long>>>
is flattened as
pack<int, int, std::tuple<int, long>>
instead of
pack<int, int, int, long>
you have to remove the template-template parameter in the last flatt_helper
specialization and simplify it as follows
template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
struct flatt_helper<pack<Ts1...>, pack<Ts2...>, Ts3...>
: flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
{ };
The following is a full compiling example (with full flatting)
#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, "!" );
}
2
Nice answer with the building up frompack<>
but you should point out that, with the template template parameter, this will flatten everything, likeflatt<pack<int, std::vector<int>>>
is actuallypack<int, int, int>
, which may not be the expected behavior here.
– Holt
Jan 3 at 16:29
1
@holt I would even call it "wrong".
– Yakk - Adam Nevraumont
Jan 3 at 16:40
@Holt - yes, wasn't clear; answer modified; hope is clearer now
– max66
Jan 3 at 16:48
add a comment |
A possible quick implementation based on 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;
Godbolt demo
add a comment |
i'd recursively unpack and pack things back:
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...>>;
};
The type repack<pack<int, pack<int, pack<int, pack<int>>>>>::type
get transformed into:
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>
Live demo
2
This code does not generate the type you think it does. Nor does it handle `pack<int,int,int> right.
– Yakk - Adam Nevraumont
Jan 3 at 16:42
add a comment |
Late to the party?
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>>);
add a comment |
pack_cat
takes a sequence of packs or non-packs, and concatinates anything that is a pack together, plus items that are not packs.
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
takes a pack, and recursively unpacks all sub-packs and concatinates them.
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>...>;};
To test it:
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>>{};
which compile IFF the two types are the same.
add a comment |
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 > > >()... ) );
add a comment |
And now... for something completely different... (well... not completely... almost the Holt's solutions but using functions instead of structs)
You can combine std::tuple_cat()
with decltype()
in a couple of declared function to flat a pack
in a std::tuple
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>())...) );
and another declared functions that convert the flattened std::tuple
again in a pack
template <typename ... Ts>
constexpr pack<Ts...> bar (std::tuple<Ts...>);
Now you can combine in a flattener as follows
template <typename T>
using fl = decltype(bar(foo(std::declval<T>())));
The following is a full compiling example
#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, "!" );
}
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54025813%2fhow-to-flatten-nested-templates-parameters%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
7 Answers
7
active
oldest
votes
7 Answers
7
active
oldest
votes
active
oldest
votes
active
oldest
votes
I propose the following struct and using
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;
This way you can flatten pack
and other template-template, as std::tuple
, and also more complex examples (the pack<int, pack<int, int>, int>
suggested by Holt, by example).
If you want flat only pack
, avoiding that all template-template are flattened..., I mean... if you want that
pack<int, pack<int, std::tuple<int, long>>>
is flattened as
pack<int, int, std::tuple<int, long>>
instead of
pack<int, int, int, long>
you have to remove the template-template parameter in the last flatt_helper
specialization and simplify it as follows
template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
struct flatt_helper<pack<Ts1...>, pack<Ts2...>, Ts3...>
: flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
{ };
The following is a full compiling example (with full flatting)
#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, "!" );
}
2
Nice answer with the building up frompack<>
but you should point out that, with the template template parameter, this will flatten everything, likeflatt<pack<int, std::vector<int>>>
is actuallypack<int, int, int>
, which may not be the expected behavior here.
– Holt
Jan 3 at 16:29
1
@holt I would even call it "wrong".
– Yakk - Adam Nevraumont
Jan 3 at 16:40
@Holt - yes, wasn't clear; answer modified; hope is clearer now
– max66
Jan 3 at 16:48
add a comment |
I propose the following struct and using
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;
This way you can flatten pack
and other template-template, as std::tuple
, and also more complex examples (the pack<int, pack<int, int>, int>
suggested by Holt, by example).
If you want flat only pack
, avoiding that all template-template are flattened..., I mean... if you want that
pack<int, pack<int, std::tuple<int, long>>>
is flattened as
pack<int, int, std::tuple<int, long>>
instead of
pack<int, int, int, long>
you have to remove the template-template parameter in the last flatt_helper
specialization and simplify it as follows
template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
struct flatt_helper<pack<Ts1...>, pack<Ts2...>, Ts3...>
: flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
{ };
The following is a full compiling example (with full flatting)
#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, "!" );
}
2
Nice answer with the building up frompack<>
but you should point out that, with the template template parameter, this will flatten everything, likeflatt<pack<int, std::vector<int>>>
is actuallypack<int, int, int>
, which may not be the expected behavior here.
– Holt
Jan 3 at 16:29
1
@holt I would even call it "wrong".
– Yakk - Adam Nevraumont
Jan 3 at 16:40
@Holt - yes, wasn't clear; answer modified; hope is clearer now
– max66
Jan 3 at 16:48
add a comment |
I propose the following struct and using
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;
This way you can flatten pack
and other template-template, as std::tuple
, and also more complex examples (the pack<int, pack<int, int>, int>
suggested by Holt, by example).
If you want flat only pack
, avoiding that all template-template are flattened..., I mean... if you want that
pack<int, pack<int, std::tuple<int, long>>>
is flattened as
pack<int, int, std::tuple<int, long>>
instead of
pack<int, int, int, long>
you have to remove the template-template parameter in the last flatt_helper
specialization and simplify it as follows
template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
struct flatt_helper<pack<Ts1...>, pack<Ts2...>, Ts3...>
: flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
{ };
The following is a full compiling example (with full flatting)
#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, "!" );
}
I propose the following struct and using
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;
This way you can flatten pack
and other template-template, as std::tuple
, and also more complex examples (the pack<int, pack<int, int>, int>
suggested by Holt, by example).
If you want flat only pack
, avoiding that all template-template are flattened..., I mean... if you want that
pack<int, pack<int, std::tuple<int, long>>>
is flattened as
pack<int, int, std::tuple<int, long>>
instead of
pack<int, int, int, long>
you have to remove the template-template parameter in the last flatt_helper
specialization and simplify it as follows
template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
struct flatt_helper<pack<Ts1...>, pack<Ts2...>, Ts3...>
: flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
{ };
The following is a full compiling example (with full flatting)
#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, "!" );
}
edited Jan 3 at 16:47
answered Jan 3 at 16:20
max66max66
39.4k74575
39.4k74575
2
Nice answer with the building up frompack<>
but you should point out that, with the template template parameter, this will flatten everything, likeflatt<pack<int, std::vector<int>>>
is actuallypack<int, int, int>
, which may not be the expected behavior here.
– Holt
Jan 3 at 16:29
1
@holt I would even call it "wrong".
– Yakk - Adam Nevraumont
Jan 3 at 16:40
@Holt - yes, wasn't clear; answer modified; hope is clearer now
– max66
Jan 3 at 16:48
add a comment |
2
Nice answer with the building up frompack<>
but you should point out that, with the template template parameter, this will flatten everything, likeflatt<pack<int, std::vector<int>>>
is actuallypack<int, int, int>
, which may not be the expected behavior here.
– Holt
Jan 3 at 16:29
1
@holt I would even call it "wrong".
– Yakk - Adam Nevraumont
Jan 3 at 16:40
@Holt - yes, wasn't clear; answer modified; hope is clearer now
– max66
Jan 3 at 16:48
2
2
Nice answer with the building up from
pack<>
but you should point out that, with the template template parameter, this will flatten everything, like flatt<pack<int, std::vector<int>>>
is actually pack<int, int, int>
, which may not be the expected behavior here.– Holt
Jan 3 at 16:29
Nice answer with the building up from
pack<>
but you should point out that, with the template template parameter, this will flatten everything, like flatt<pack<int, std::vector<int>>>
is actually pack<int, int, int>
, which may not be the expected behavior here.– Holt
Jan 3 at 16:29
1
1
@holt I would even call it "wrong".
– Yakk - Adam Nevraumont
Jan 3 at 16:40
@holt I would even call it "wrong".
– Yakk - Adam Nevraumont
Jan 3 at 16:40
@Holt - yes, wasn't clear; answer modified; hope is clearer now
– max66
Jan 3 at 16:48
@Holt - yes, wasn't clear; answer modified; hope is clearer now
– max66
Jan 3 at 16:48
add a comment |
A possible quick implementation based on 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;
Godbolt demo
add a comment |
A possible quick implementation based on 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;
Godbolt demo
add a comment |
A possible quick implementation based on 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;
Godbolt demo
A possible quick implementation based on 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;
Godbolt demo
edited Jan 3 at 16:16
answered Jan 3 at 16:09
HoltHolt
25.9k65195
25.9k65195
add a comment |
add a comment |
i'd recursively unpack and pack things back:
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...>>;
};
The type repack<pack<int, pack<int, pack<int, pack<int>>>>>::type
get transformed into:
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>
Live demo
2
This code does not generate the type you think it does. Nor does it handle `pack<int,int,int> right.
– Yakk - Adam Nevraumont
Jan 3 at 16:42
add a comment |
i'd recursively unpack and pack things back:
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...>>;
};
The type repack<pack<int, pack<int, pack<int, pack<int>>>>>::type
get transformed into:
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>
Live demo
2
This code does not generate the type you think it does. Nor does it handle `pack<int,int,int> right.
– Yakk - Adam Nevraumont
Jan 3 at 16:42
add a comment |
i'd recursively unpack and pack things back:
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...>>;
};
The type repack<pack<int, pack<int, pack<int, pack<int>>>>>::type
get transformed into:
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>
Live demo
i'd recursively unpack and pack things back:
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...>>;
};
The type repack<pack<int, pack<int, pack<int, pack<int>>>>>::type
get transformed into:
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>
Live demo
answered Jan 3 at 16:12


YSCYSC
25.7k657112
25.7k657112
2
This code does not generate the type you think it does. Nor does it handle `pack<int,int,int> right.
– Yakk - Adam Nevraumont
Jan 3 at 16:42
add a comment |
2
This code does not generate the type you think it does. Nor does it handle `pack<int,int,int> right.
– Yakk - Adam Nevraumont
Jan 3 at 16:42
2
2
This code does not generate the type you think it does. Nor does it handle `pack<int,int,int> right.
– Yakk - Adam Nevraumont
Jan 3 at 16:42
This code does not generate the type you think it does. Nor does it handle `pack<int,int,int> right.
– Yakk - Adam Nevraumont
Jan 3 at 16:42
add a comment |
Late to the party?
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>>);
add a comment |
Late to the party?
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>>);
add a comment |
Late to the party?
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>>);
Late to the party?
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>>);
answered Jan 3 at 21:12
JansJans
9,19422735
9,19422735
add a comment |
add a comment |
pack_cat
takes a sequence of packs or non-packs, and concatinates anything that is a pack together, plus items that are not packs.
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
takes a pack, and recursively unpacks all sub-packs and concatinates them.
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>...>;};
To test it:
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>>{};
which compile IFF the two types are the same.
add a comment |
pack_cat
takes a sequence of packs or non-packs, and concatinates anything that is a pack together, plus items that are not packs.
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
takes a pack, and recursively unpacks all sub-packs and concatinates them.
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>...>;};
To test it:
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>>{};
which compile IFF the two types are the same.
add a comment |
pack_cat
takes a sequence of packs or non-packs, and concatinates anything that is a pack together, plus items that are not packs.
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
takes a pack, and recursively unpacks all sub-packs and concatinates them.
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>...>;};
To test it:
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>>{};
which compile IFF the two types are the same.
pack_cat
takes a sequence of packs or non-packs, and concatinates anything that is a pack together, plus items that are not packs.
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
takes a pack, and recursively unpacks all sub-packs and concatinates them.
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>...>;};
To test it:
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>>{};
which compile IFF the two types are the same.
answered Jan 3 at 16:54
Yakk - Adam NevraumontYakk - Adam Nevraumont
189k21200385
189k21200385
add a comment |
add a comment |
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 > > >()... ) );
add a comment |
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 > > >()... ) );
add a comment |
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 > > >()... ) );
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 > > >()... ) );
answered Jan 3 at 17:11


Red.WaveRed.Wave
89537
89537
add a comment |
add a comment |
And now... for something completely different... (well... not completely... almost the Holt's solutions but using functions instead of structs)
You can combine std::tuple_cat()
with decltype()
in a couple of declared function to flat a pack
in a std::tuple
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>())...) );
and another declared functions that convert the flattened std::tuple
again in a pack
template <typename ... Ts>
constexpr pack<Ts...> bar (std::tuple<Ts...>);
Now you can combine in a flattener as follows
template <typename T>
using fl = decltype(bar(foo(std::declval<T>())));
The following is a full compiling example
#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, "!" );
}
add a comment |
And now... for something completely different... (well... not completely... almost the Holt's solutions but using functions instead of structs)
You can combine std::tuple_cat()
with decltype()
in a couple of declared function to flat a pack
in a std::tuple
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>())...) );
and another declared functions that convert the flattened std::tuple
again in a pack
template <typename ... Ts>
constexpr pack<Ts...> bar (std::tuple<Ts...>);
Now you can combine in a flattener as follows
template <typename T>
using fl = decltype(bar(foo(std::declval<T>())));
The following is a full compiling example
#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, "!" );
}
add a comment |
And now... for something completely different... (well... not completely... almost the Holt's solutions but using functions instead of structs)
You can combine std::tuple_cat()
with decltype()
in a couple of declared function to flat a pack
in a std::tuple
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>())...) );
and another declared functions that convert the flattened std::tuple
again in a pack
template <typename ... Ts>
constexpr pack<Ts...> bar (std::tuple<Ts...>);
Now you can combine in a flattener as follows
template <typename T>
using fl = decltype(bar(foo(std::declval<T>())));
The following is a full compiling example
#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, "!" );
}
And now... for something completely different... (well... not completely... almost the Holt's solutions but using functions instead of structs)
You can combine std::tuple_cat()
with decltype()
in a couple of declared function to flat a pack
in a std::tuple
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>())...) );
and another declared functions that convert the flattened std::tuple
again in a pack
template <typename ... Ts>
constexpr pack<Ts...> bar (std::tuple<Ts...>);
Now you can combine in a flattener as follows
template <typename T>
using fl = decltype(bar(foo(std::declval<T>())));
The following is a full compiling example
#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, "!" );
}
answered Jan 3 at 20:15
max66max66
39.4k74575
39.4k74575
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54025813%2fhow-to-flatten-nested-templates-parameters%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
Do you also want to convert stuff like
pack<int, pack<int, int>, int>
?– Holt
Jan 3 at 16:02