How to unroll a parameter pack from right to left
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
I am trying to do a parameter pack unrolling by dispatching to a class recursively. I'd like to do that from right to left since some of the operations do pre-pending.
template <typename... T>
class Foo;
template <typename T>
class Foo<T> {/* base case implementation*/};
template <typename T, typename R, typename... Rs>
class Foo<T, Rs..., R> {
private:
Foo<T, Rs...> foo_;
}
Unfortunately, the above gets me:
class template partial specialization contains template parameters that cannot be deduced;
this partial specialization will never be used
This seems odd to me, I would assume that even though the arguments has switched order, Foo<T, Rs..., R>
should still match the template specialization.
I've looked at some similar questions:
Specifically, C++ template partial specialization: Why cant I match the last type in variadic-template?
However, the highest voted (non-accepted) answer doesn't make sense to me. Sure I understand that the template parameter pack declaration must be the last in the declaration, but I do that for the template specialization.
I'm not sure why the compiler cannot map Foo<T, Rs..., R>
to the initial template declaration Foo<T...>
and enforces the parameter pack declaration order there.
Other answers on that thread offer how to extract the last value, but that still doesn't allow you to do recursive parameter pack unrolling, which is sort of the whole point here. Is it just impossible to unroll a parameter pack from right to left?
c++ c++11
add a comment |
I am trying to do a parameter pack unrolling by dispatching to a class recursively. I'd like to do that from right to left since some of the operations do pre-pending.
template <typename... T>
class Foo;
template <typename T>
class Foo<T> {/* base case implementation*/};
template <typename T, typename R, typename... Rs>
class Foo<T, Rs..., R> {
private:
Foo<T, Rs...> foo_;
}
Unfortunately, the above gets me:
class template partial specialization contains template parameters that cannot be deduced;
this partial specialization will never be used
This seems odd to me, I would assume that even though the arguments has switched order, Foo<T, Rs..., R>
should still match the template specialization.
I've looked at some similar questions:
Specifically, C++ template partial specialization: Why cant I match the last type in variadic-template?
However, the highest voted (non-accepted) answer doesn't make sense to me. Sure I understand that the template parameter pack declaration must be the last in the declaration, but I do that for the template specialization.
I'm not sure why the compiler cannot map Foo<T, Rs..., R>
to the initial template declaration Foo<T...>
and enforces the parameter pack declaration order there.
Other answers on that thread offer how to extract the last value, but that still doesn't allow you to do recursive parameter pack unrolling, which is sort of the whole point here. Is it just impossible to unroll a parameter pack from right to left?
c++ c++11
2
Well you can revert the order of the argument then unroll left to right. You may look an implementation of revert here : bitbucket.org/MartinMorterol/glp/src/dev/include/… or here github.com/edouarda/brigand/blob/master/include/brigand/…
– Martin Morterol
Apr 19 at 12:53
add a comment |
I am trying to do a parameter pack unrolling by dispatching to a class recursively. I'd like to do that from right to left since some of the operations do pre-pending.
template <typename... T>
class Foo;
template <typename T>
class Foo<T> {/* base case implementation*/};
template <typename T, typename R, typename... Rs>
class Foo<T, Rs..., R> {
private:
Foo<T, Rs...> foo_;
}
Unfortunately, the above gets me:
class template partial specialization contains template parameters that cannot be deduced;
this partial specialization will never be used
This seems odd to me, I would assume that even though the arguments has switched order, Foo<T, Rs..., R>
should still match the template specialization.
I've looked at some similar questions:
Specifically, C++ template partial specialization: Why cant I match the last type in variadic-template?
However, the highest voted (non-accepted) answer doesn't make sense to me. Sure I understand that the template parameter pack declaration must be the last in the declaration, but I do that for the template specialization.
I'm not sure why the compiler cannot map Foo<T, Rs..., R>
to the initial template declaration Foo<T...>
and enforces the parameter pack declaration order there.
Other answers on that thread offer how to extract the last value, but that still doesn't allow you to do recursive parameter pack unrolling, which is sort of the whole point here. Is it just impossible to unroll a parameter pack from right to left?
c++ c++11
I am trying to do a parameter pack unrolling by dispatching to a class recursively. I'd like to do that from right to left since some of the operations do pre-pending.
template <typename... T>
class Foo;
template <typename T>
class Foo<T> {/* base case implementation*/};
template <typename T, typename R, typename... Rs>
class Foo<T, Rs..., R> {
private:
Foo<T, Rs...> foo_;
}
Unfortunately, the above gets me:
class template partial specialization contains template parameters that cannot be deduced;
this partial specialization will never be used
This seems odd to me, I would assume that even though the arguments has switched order, Foo<T, Rs..., R>
should still match the template specialization.
I've looked at some similar questions:
Specifically, C++ template partial specialization: Why cant I match the last type in variadic-template?
However, the highest voted (non-accepted) answer doesn't make sense to me. Sure I understand that the template parameter pack declaration must be the last in the declaration, but I do that for the template specialization.
I'm not sure why the compiler cannot map Foo<T, Rs..., R>
to the initial template declaration Foo<T...>
and enforces the parameter pack declaration order there.
Other answers on that thread offer how to extract the last value, but that still doesn't allow you to do recursive parameter pack unrolling, which is sort of the whole point here. Is it just impossible to unroll a parameter pack from right to left?
c++ c++11
c++ c++11
edited Apr 19 at 13:24
Bob__
5,30831527
5,30831527
asked Apr 19 at 12:47
IdeaHatIdeaHat
5,7731342
5,7731342
2
Well you can revert the order of the argument then unroll left to right. You may look an implementation of revert here : bitbucket.org/MartinMorterol/glp/src/dev/include/… or here github.com/edouarda/brigand/blob/master/include/brigand/…
– Martin Morterol
Apr 19 at 12:53
add a comment |
2
Well you can revert the order of the argument then unroll left to right. You may look an implementation of revert here : bitbucket.org/MartinMorterol/glp/src/dev/include/… or here github.com/edouarda/brigand/blob/master/include/brigand/…
– Martin Morterol
Apr 19 at 12:53
2
2
Well you can revert the order of the argument then unroll left to right. You may look an implementation of revert here : bitbucket.org/MartinMorterol/glp/src/dev/include/… or here github.com/edouarda/brigand/blob/master/include/brigand/…
– Martin Morterol
Apr 19 at 12:53
Well you can revert the order of the argument then unroll left to right. You may look an implementation of revert here : bitbucket.org/MartinMorterol/glp/src/dev/include/… or here github.com/edouarda/brigand/blob/master/include/brigand/…
– Martin Morterol
Apr 19 at 12:53
add a comment |
3 Answers
3
active
oldest
votes
Here is an utility to instatiate a template with a reverse order of template parameters:
#include <type_traits>
#include <tuple>
template <template <typename...> typename Template, typename ...Arg>
struct RevertHelper;
template <template <typename > typename Template, typename Arg>
struct RevertHelper<Template, Arg>
{
using Result = Template<Arg>;
};
template <template <typename... > typename Template, typename Head, typename ...Tail>
struct RevertHelper<Template, Head, Tail...>
{
private:
template <typename ...XArgs>
using BindToTail = Template<XArgs..., Head>;
public:
using Result = typename RevertHelper<BindToTail, Tail...>::Result;
};
static_assert(std::is_same_v<typename RevertHelper<std::tuple, int, double>::Result, std::tuple<double, int>>, "");
So if you need to instantiate Foo
with template pack Args...
being reversed you can use
typename RevertHelper<Foo, Args...>::Result
To do the parameter pack expansion the way you want, dispatch to the reversed implementation:
namespace internal {
template <typename... T>
class FooHelper;
template <typename T>
class FooHelper<T> {/* base implementation */}
template <typename L, typename R, typename... Rs>
class FooHelper<T> {
private:
Foo<T, Rs...> foo_helper_;
};
}
template <typename... T>
class Foo {
typename RevertHelper<internal::FooHelper, T...>::Result foo_helper_;
};
So the idea is that the actually usable class inverses the order and then dispatches to a class that reverses the order, and do the unpacking in that helper class?
– IdeaHat
Apr 19 at 13:22
"thanks i hate it" :-) . Added the code example. So much boilerplate to do something so simple.
– IdeaHat
Apr 19 at 13:32
@IdeaHat, yes I meant something like that. You can even make "Foo" a template alias to a RevertHelper<internal::FooHelper, T...>
– Dmitry Gordon
Apr 19 at 13:34
Not while providing a base case specialization
– IdeaHat
Apr 19 at 14:49
add a comment |
I'm not sure why the compiler cannot map
Foo<T, Rs..., R>
to the initial template declarationFoo<T...>
and enforces the parameter pack declaration order there.
Because partial ordering is already a really complex algorithm and adding extra complexity to that is fraught with peril. There was a proposal to make this work, which had this example:
template <class A, class... B, class C> void foo(A a, B... b, C c);
foo(1, 2, 3, 4); // b is deduced as [2, 3]
Straightforward enough right? Now, what if C
has a default argument? What does this do:
template <class A, class... B, class C=int> void foo(A a, B... b, C c=5);
foo(1, 2, 3, 4);
There are two interpretations of this:
b
is deduced as the pack{2, 3}
andc
is deduced as4
b
is deduced as the pack{2, 3, 4}
andc
is deduced as5
Which is intended? Or do we just disallow default arguments after a function parameter pack?
Unfortunately, we have no nice pack indexing mechanism. In the meantime, just use Boost.Mp11:
template <typename... T>
class Foo;
template <typename T>
class Foo<T> {/* base case implementation*/};
template <typename T, typename... Rs>
class Foo<T, Rs...> {
private:
using R = mp_back<Foo>;
mp_pop_back<Foo> foo_;
};
"Or do we just disallow default arguments after a function parameter pack?" - the obvious answer to me here seems "yes". But I guess that didn't fly with EWG?
– Vittorio Romeo
Apr 20 at 10:37
add a comment |
Pattern matching in C++ template patterns is intentionally simplified for sake of simplicity of algorithm and understanding.
Take a look at hypothetical algorithm if this could be possible:
- Get some declaration: using
X = Foo<int, char, bool, double>
; - Compiler checks specializations: first one is Foo - it's dropped.
- Compiler checks specializations: second one is your
Foo<T, Rs..., R>
T
isint
, we're fine.
R
's can be emtpy, let's try to skip it.
R
ischar
, but we're at the end of specialization parameters, let's get back to 2.
R
's is char
R
isbool
, but we're at the end of specialization parameters, let's get back to 2.
R
's ischar
,bool
R
isdouble
, we're fine, select this one
But this is only one scenario: another one would be to eat all parameters to the end and cut off one by one in order to try to match it. This can be problematic, because such template specialization would be inherently ambiguous with another possible specialization that doesn't seem to be an ambiguity here:
template<typename T, typename S>
class Foo<T, S> {};
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%2f55762106%2fhow-to-unroll-a-parameter-pack-from-right-to-left%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
Here is an utility to instatiate a template with a reverse order of template parameters:
#include <type_traits>
#include <tuple>
template <template <typename...> typename Template, typename ...Arg>
struct RevertHelper;
template <template <typename > typename Template, typename Arg>
struct RevertHelper<Template, Arg>
{
using Result = Template<Arg>;
};
template <template <typename... > typename Template, typename Head, typename ...Tail>
struct RevertHelper<Template, Head, Tail...>
{
private:
template <typename ...XArgs>
using BindToTail = Template<XArgs..., Head>;
public:
using Result = typename RevertHelper<BindToTail, Tail...>::Result;
};
static_assert(std::is_same_v<typename RevertHelper<std::tuple, int, double>::Result, std::tuple<double, int>>, "");
So if you need to instantiate Foo
with template pack Args...
being reversed you can use
typename RevertHelper<Foo, Args...>::Result
To do the parameter pack expansion the way you want, dispatch to the reversed implementation:
namespace internal {
template <typename... T>
class FooHelper;
template <typename T>
class FooHelper<T> {/* base implementation */}
template <typename L, typename R, typename... Rs>
class FooHelper<T> {
private:
Foo<T, Rs...> foo_helper_;
};
}
template <typename... T>
class Foo {
typename RevertHelper<internal::FooHelper, T...>::Result foo_helper_;
};
So the idea is that the actually usable class inverses the order and then dispatches to a class that reverses the order, and do the unpacking in that helper class?
– IdeaHat
Apr 19 at 13:22
"thanks i hate it" :-) . Added the code example. So much boilerplate to do something so simple.
– IdeaHat
Apr 19 at 13:32
@IdeaHat, yes I meant something like that. You can even make "Foo" a template alias to a RevertHelper<internal::FooHelper, T...>
– Dmitry Gordon
Apr 19 at 13:34
Not while providing a base case specialization
– IdeaHat
Apr 19 at 14:49
add a comment |
Here is an utility to instatiate a template with a reverse order of template parameters:
#include <type_traits>
#include <tuple>
template <template <typename...> typename Template, typename ...Arg>
struct RevertHelper;
template <template <typename > typename Template, typename Arg>
struct RevertHelper<Template, Arg>
{
using Result = Template<Arg>;
};
template <template <typename... > typename Template, typename Head, typename ...Tail>
struct RevertHelper<Template, Head, Tail...>
{
private:
template <typename ...XArgs>
using BindToTail = Template<XArgs..., Head>;
public:
using Result = typename RevertHelper<BindToTail, Tail...>::Result;
};
static_assert(std::is_same_v<typename RevertHelper<std::tuple, int, double>::Result, std::tuple<double, int>>, "");
So if you need to instantiate Foo
with template pack Args...
being reversed you can use
typename RevertHelper<Foo, Args...>::Result
To do the parameter pack expansion the way you want, dispatch to the reversed implementation:
namespace internal {
template <typename... T>
class FooHelper;
template <typename T>
class FooHelper<T> {/* base implementation */}
template <typename L, typename R, typename... Rs>
class FooHelper<T> {
private:
Foo<T, Rs...> foo_helper_;
};
}
template <typename... T>
class Foo {
typename RevertHelper<internal::FooHelper, T...>::Result foo_helper_;
};
So the idea is that the actually usable class inverses the order and then dispatches to a class that reverses the order, and do the unpacking in that helper class?
– IdeaHat
Apr 19 at 13:22
"thanks i hate it" :-) . Added the code example. So much boilerplate to do something so simple.
– IdeaHat
Apr 19 at 13:32
@IdeaHat, yes I meant something like that. You can even make "Foo" a template alias to a RevertHelper<internal::FooHelper, T...>
– Dmitry Gordon
Apr 19 at 13:34
Not while providing a base case specialization
– IdeaHat
Apr 19 at 14:49
add a comment |
Here is an utility to instatiate a template with a reverse order of template parameters:
#include <type_traits>
#include <tuple>
template <template <typename...> typename Template, typename ...Arg>
struct RevertHelper;
template <template <typename > typename Template, typename Arg>
struct RevertHelper<Template, Arg>
{
using Result = Template<Arg>;
};
template <template <typename... > typename Template, typename Head, typename ...Tail>
struct RevertHelper<Template, Head, Tail...>
{
private:
template <typename ...XArgs>
using BindToTail = Template<XArgs..., Head>;
public:
using Result = typename RevertHelper<BindToTail, Tail...>::Result;
};
static_assert(std::is_same_v<typename RevertHelper<std::tuple, int, double>::Result, std::tuple<double, int>>, "");
So if you need to instantiate Foo
with template pack Args...
being reversed you can use
typename RevertHelper<Foo, Args...>::Result
To do the parameter pack expansion the way you want, dispatch to the reversed implementation:
namespace internal {
template <typename... T>
class FooHelper;
template <typename T>
class FooHelper<T> {/* base implementation */}
template <typename L, typename R, typename... Rs>
class FooHelper<T> {
private:
Foo<T, Rs...> foo_helper_;
};
}
template <typename... T>
class Foo {
typename RevertHelper<internal::FooHelper, T...>::Result foo_helper_;
};
Here is an utility to instatiate a template with a reverse order of template parameters:
#include <type_traits>
#include <tuple>
template <template <typename...> typename Template, typename ...Arg>
struct RevertHelper;
template <template <typename > typename Template, typename Arg>
struct RevertHelper<Template, Arg>
{
using Result = Template<Arg>;
};
template <template <typename... > typename Template, typename Head, typename ...Tail>
struct RevertHelper<Template, Head, Tail...>
{
private:
template <typename ...XArgs>
using BindToTail = Template<XArgs..., Head>;
public:
using Result = typename RevertHelper<BindToTail, Tail...>::Result;
};
static_assert(std::is_same_v<typename RevertHelper<std::tuple, int, double>::Result, std::tuple<double, int>>, "");
So if you need to instantiate Foo
with template pack Args...
being reversed you can use
typename RevertHelper<Foo, Args...>::Result
To do the parameter pack expansion the way you want, dispatch to the reversed implementation:
namespace internal {
template <typename... T>
class FooHelper;
template <typename T>
class FooHelper<T> {/* base implementation */}
template <typename L, typename R, typename... Rs>
class FooHelper<T> {
private:
Foo<T, Rs...> foo_helper_;
};
}
template <typename... T>
class Foo {
typename RevertHelper<internal::FooHelper, T...>::Result foo_helper_;
};
edited Apr 19 at 13:30
IdeaHat
5,7731342
5,7731342
answered Apr 19 at 13:05
Dmitry GordonDmitry Gordon
1,584616
1,584616
So the idea is that the actually usable class inverses the order and then dispatches to a class that reverses the order, and do the unpacking in that helper class?
– IdeaHat
Apr 19 at 13:22
"thanks i hate it" :-) . Added the code example. So much boilerplate to do something so simple.
– IdeaHat
Apr 19 at 13:32
@IdeaHat, yes I meant something like that. You can even make "Foo" a template alias to a RevertHelper<internal::FooHelper, T...>
– Dmitry Gordon
Apr 19 at 13:34
Not while providing a base case specialization
– IdeaHat
Apr 19 at 14:49
add a comment |
So the idea is that the actually usable class inverses the order and then dispatches to a class that reverses the order, and do the unpacking in that helper class?
– IdeaHat
Apr 19 at 13:22
"thanks i hate it" :-) . Added the code example. So much boilerplate to do something so simple.
– IdeaHat
Apr 19 at 13:32
@IdeaHat, yes I meant something like that. You can even make "Foo" a template alias to a RevertHelper<internal::FooHelper, T...>
– Dmitry Gordon
Apr 19 at 13:34
Not while providing a base case specialization
– IdeaHat
Apr 19 at 14:49
So the idea is that the actually usable class inverses the order and then dispatches to a class that reverses the order, and do the unpacking in that helper class?
– IdeaHat
Apr 19 at 13:22
So the idea is that the actually usable class inverses the order and then dispatches to a class that reverses the order, and do the unpacking in that helper class?
– IdeaHat
Apr 19 at 13:22
"thanks i hate it" :-) . Added the code example. So much boilerplate to do something so simple.
– IdeaHat
Apr 19 at 13:32
"thanks i hate it" :-) . Added the code example. So much boilerplate to do something so simple.
– IdeaHat
Apr 19 at 13:32
@IdeaHat, yes I meant something like that. You can even make "Foo" a template alias to a RevertHelper<internal::FooHelper, T...>
– Dmitry Gordon
Apr 19 at 13:34
@IdeaHat, yes I meant something like that. You can even make "Foo" a template alias to a RevertHelper<internal::FooHelper, T...>
– Dmitry Gordon
Apr 19 at 13:34
Not while providing a base case specialization
– IdeaHat
Apr 19 at 14:49
Not while providing a base case specialization
– IdeaHat
Apr 19 at 14:49
add a comment |
I'm not sure why the compiler cannot map
Foo<T, Rs..., R>
to the initial template declarationFoo<T...>
and enforces the parameter pack declaration order there.
Because partial ordering is already a really complex algorithm and adding extra complexity to that is fraught with peril. There was a proposal to make this work, which had this example:
template <class A, class... B, class C> void foo(A a, B... b, C c);
foo(1, 2, 3, 4); // b is deduced as [2, 3]
Straightforward enough right? Now, what if C
has a default argument? What does this do:
template <class A, class... B, class C=int> void foo(A a, B... b, C c=5);
foo(1, 2, 3, 4);
There are two interpretations of this:
b
is deduced as the pack{2, 3}
andc
is deduced as4
b
is deduced as the pack{2, 3, 4}
andc
is deduced as5
Which is intended? Or do we just disallow default arguments after a function parameter pack?
Unfortunately, we have no nice pack indexing mechanism. In the meantime, just use Boost.Mp11:
template <typename... T>
class Foo;
template <typename T>
class Foo<T> {/* base case implementation*/};
template <typename T, typename... Rs>
class Foo<T, Rs...> {
private:
using R = mp_back<Foo>;
mp_pop_back<Foo> foo_;
};
"Or do we just disallow default arguments after a function parameter pack?" - the obvious answer to me here seems "yes". But I guess that didn't fly with EWG?
– Vittorio Romeo
Apr 20 at 10:37
add a comment |
I'm not sure why the compiler cannot map
Foo<T, Rs..., R>
to the initial template declarationFoo<T...>
and enforces the parameter pack declaration order there.
Because partial ordering is already a really complex algorithm and adding extra complexity to that is fraught with peril. There was a proposal to make this work, which had this example:
template <class A, class... B, class C> void foo(A a, B... b, C c);
foo(1, 2, 3, 4); // b is deduced as [2, 3]
Straightforward enough right? Now, what if C
has a default argument? What does this do:
template <class A, class... B, class C=int> void foo(A a, B... b, C c=5);
foo(1, 2, 3, 4);
There are two interpretations of this:
b
is deduced as the pack{2, 3}
andc
is deduced as4
b
is deduced as the pack{2, 3, 4}
andc
is deduced as5
Which is intended? Or do we just disallow default arguments after a function parameter pack?
Unfortunately, we have no nice pack indexing mechanism. In the meantime, just use Boost.Mp11:
template <typename... T>
class Foo;
template <typename T>
class Foo<T> {/* base case implementation*/};
template <typename T, typename... Rs>
class Foo<T, Rs...> {
private:
using R = mp_back<Foo>;
mp_pop_back<Foo> foo_;
};
"Or do we just disallow default arguments after a function parameter pack?" - the obvious answer to me here seems "yes". But I guess that didn't fly with EWG?
– Vittorio Romeo
Apr 20 at 10:37
add a comment |
I'm not sure why the compiler cannot map
Foo<T, Rs..., R>
to the initial template declarationFoo<T...>
and enforces the parameter pack declaration order there.
Because partial ordering is already a really complex algorithm and adding extra complexity to that is fraught with peril. There was a proposal to make this work, which had this example:
template <class A, class... B, class C> void foo(A a, B... b, C c);
foo(1, 2, 3, 4); // b is deduced as [2, 3]
Straightforward enough right? Now, what if C
has a default argument? What does this do:
template <class A, class... B, class C=int> void foo(A a, B... b, C c=5);
foo(1, 2, 3, 4);
There are two interpretations of this:
b
is deduced as the pack{2, 3}
andc
is deduced as4
b
is deduced as the pack{2, 3, 4}
andc
is deduced as5
Which is intended? Or do we just disallow default arguments after a function parameter pack?
Unfortunately, we have no nice pack indexing mechanism. In the meantime, just use Boost.Mp11:
template <typename... T>
class Foo;
template <typename T>
class Foo<T> {/* base case implementation*/};
template <typename T, typename... Rs>
class Foo<T, Rs...> {
private:
using R = mp_back<Foo>;
mp_pop_back<Foo> foo_;
};
I'm not sure why the compiler cannot map
Foo<T, Rs..., R>
to the initial template declarationFoo<T...>
and enforces the parameter pack declaration order there.
Because partial ordering is already a really complex algorithm and adding extra complexity to that is fraught with peril. There was a proposal to make this work, which had this example:
template <class A, class... B, class C> void foo(A a, B... b, C c);
foo(1, 2, 3, 4); // b is deduced as [2, 3]
Straightforward enough right? Now, what if C
has a default argument? What does this do:
template <class A, class... B, class C=int> void foo(A a, B... b, C c=5);
foo(1, 2, 3, 4);
There are two interpretations of this:
b
is deduced as the pack{2, 3}
andc
is deduced as4
b
is deduced as the pack{2, 3, 4}
andc
is deduced as5
Which is intended? Or do we just disallow default arguments after a function parameter pack?
Unfortunately, we have no nice pack indexing mechanism. In the meantime, just use Boost.Mp11:
template <typename... T>
class Foo;
template <typename T>
class Foo<T> {/* base case implementation*/};
template <typename T, typename... Rs>
class Foo<T, Rs...> {
private:
using R = mp_back<Foo>;
mp_pop_back<Foo> foo_;
};
answered Apr 19 at 13:59
BarryBarry
189k21339622
189k21339622
"Or do we just disallow default arguments after a function parameter pack?" - the obvious answer to me here seems "yes". But I guess that didn't fly with EWG?
– Vittorio Romeo
Apr 20 at 10:37
add a comment |
"Or do we just disallow default arguments after a function parameter pack?" - the obvious answer to me here seems "yes". But I guess that didn't fly with EWG?
– Vittorio Romeo
Apr 20 at 10:37
"Or do we just disallow default arguments after a function parameter pack?" - the obvious answer to me here seems "yes". But I guess that didn't fly with EWG?
– Vittorio Romeo
Apr 20 at 10:37
"Or do we just disallow default arguments after a function parameter pack?" - the obvious answer to me here seems "yes". But I guess that didn't fly with EWG?
– Vittorio Romeo
Apr 20 at 10:37
add a comment |
Pattern matching in C++ template patterns is intentionally simplified for sake of simplicity of algorithm and understanding.
Take a look at hypothetical algorithm if this could be possible:
- Get some declaration: using
X = Foo<int, char, bool, double>
; - Compiler checks specializations: first one is Foo - it's dropped.
- Compiler checks specializations: second one is your
Foo<T, Rs..., R>
T
isint
, we're fine.
R
's can be emtpy, let's try to skip it.
R
ischar
, but we're at the end of specialization parameters, let's get back to 2.
R
's is char
R
isbool
, but we're at the end of specialization parameters, let's get back to 2.
R
's ischar
,bool
R
isdouble
, we're fine, select this one
But this is only one scenario: another one would be to eat all parameters to the end and cut off one by one in order to try to match it. This can be problematic, because such template specialization would be inherently ambiguous with another possible specialization that doesn't seem to be an ambiguity here:
template<typename T, typename S>
class Foo<T, S> {};
add a comment |
Pattern matching in C++ template patterns is intentionally simplified for sake of simplicity of algorithm and understanding.
Take a look at hypothetical algorithm if this could be possible:
- Get some declaration: using
X = Foo<int, char, bool, double>
; - Compiler checks specializations: first one is Foo - it's dropped.
- Compiler checks specializations: second one is your
Foo<T, Rs..., R>
T
isint
, we're fine.
R
's can be emtpy, let's try to skip it.
R
ischar
, but we're at the end of specialization parameters, let's get back to 2.
R
's is char
R
isbool
, but we're at the end of specialization parameters, let's get back to 2.
R
's ischar
,bool
R
isdouble
, we're fine, select this one
But this is only one scenario: another one would be to eat all parameters to the end and cut off one by one in order to try to match it. This can be problematic, because such template specialization would be inherently ambiguous with another possible specialization that doesn't seem to be an ambiguity here:
template<typename T, typename S>
class Foo<T, S> {};
add a comment |
Pattern matching in C++ template patterns is intentionally simplified for sake of simplicity of algorithm and understanding.
Take a look at hypothetical algorithm if this could be possible:
- Get some declaration: using
X = Foo<int, char, bool, double>
; - Compiler checks specializations: first one is Foo - it's dropped.
- Compiler checks specializations: second one is your
Foo<T, Rs..., R>
T
isint
, we're fine.
R
's can be emtpy, let's try to skip it.
R
ischar
, but we're at the end of specialization parameters, let's get back to 2.
R
's is char
R
isbool
, but we're at the end of specialization parameters, let's get back to 2.
R
's ischar
,bool
R
isdouble
, we're fine, select this one
But this is only one scenario: another one would be to eat all parameters to the end and cut off one by one in order to try to match it. This can be problematic, because such template specialization would be inherently ambiguous with another possible specialization that doesn't seem to be an ambiguity here:
template<typename T, typename S>
class Foo<T, S> {};
Pattern matching in C++ template patterns is intentionally simplified for sake of simplicity of algorithm and understanding.
Take a look at hypothetical algorithm if this could be possible:
- Get some declaration: using
X = Foo<int, char, bool, double>
; - Compiler checks specializations: first one is Foo - it's dropped.
- Compiler checks specializations: second one is your
Foo<T, Rs..., R>
T
isint
, we're fine.
R
's can be emtpy, let's try to skip it.
R
ischar
, but we're at the end of specialization parameters, let's get back to 2.
R
's is char
R
isbool
, but we're at the end of specialization parameters, let's get back to 2.
R
's ischar
,bool
R
isdouble
, we're fine, select this one
But this is only one scenario: another one would be to eat all parameters to the end and cut off one by one in order to try to match it. This can be problematic, because such template specialization would be inherently ambiguous with another possible specialization that doesn't seem to be an ambiguity here:
template<typename T, typename S>
class Foo<T, S> {};
edited Apr 19 at 13:20
Stack Danny
2,173932
2,173932
answered Apr 19 at 13:04
Michał ŁośMichał Łoś
518313
518313
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%2f55762106%2fhow-to-unroll-a-parameter-pack-from-right-to-left%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
Well you can revert the order of the argument then unroll left to right. You may look an implementation of revert here : bitbucket.org/MartinMorterol/glp/src/dev/include/… or here github.com/edouarda/brigand/blob/master/include/brigand/…
– Martin Morterol
Apr 19 at 12:53