Split variadic parameter pack using template specialization





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







0















I'm trying to define a sort of template 'map' primitive (as in map-reduce). The idea is that I want to apply a function to every item of a template parameter pack. The function can be any callable object. It can return any type (though the return type will be ignored), and it can take additional arguments on top of the item in question.



The tricky part is that I effectively have two parameter packs that I need to deal with. They'll initially be packed together, but I want to split them using template specialization. What follows is my attempt at doing this.



In case it isn't obvious (due to the auto keyword in the template parameter list), this is using C++17.



#include <utility>

template <class Signature, auto f, class... ArgsAndItems>
struct Map;

template
<
class ReturnType,
class Item,
class... ArgumentTypes,
auto f,
class... Items
>
struct Map
<
ReturnType (Item, ArgumentTypes...),
f,
ArgumentTypes...,
Item,
Items...
>
{
static void
function (ArgumentTypes &&... arguments, Item && item, Items &&... items);
};

template <class ReturnType, class Item, class... ArgumentTypes, auto f>
struct Map<ReturnType (Item, ArgumentTypes...), f, ArgumentTypes...>
{
static void
function (ArgumentTypes &&... arguments);
};

template
<
class ReturnType,
class Item,
class... ArgumentTypes,
auto f,
class... Items
>
void
Map
<
ReturnType (Item, ArgumentTypes...),
f,
ArgumentTypes...,
Item,
Items...
>::function (ArgumentTypes &&... arguments, Item && item, Items &&... items)
{
f (std::forward<Item> (item), std::forward<ArgumentTypes> (arguments)...);
Map
<
ReturnType (Item, ArgumentTypes ...),
f,
ArgumentTypes...,
Items...
>::function
(
std::forward<ArgumentTypes> (arguments)...,
std::forward<Items> (items)...
);
}

template <class ReturnType, class Item, class... ArgumentTypes, auto f>
void
Map
<
ReturnType (Item, ArgumentTypes...),
f,
ArgumentTypes...
>::function (ArgumentTypes &&... arguments)
{
}


The idea is to have a wrapper that looks something like



template <auto f, class ... ArgsAndItems>
void
map (ArgsAndItems && ... args_and_items)
{
Map
<
decltype (decltype (f)::operator ()),
f,
ArgsAndItems...
>::function (std::forward <ArgsAndItems> (args_and_items) ...);
}


Which I would then use as



map <foo> (args_for_foo..., items_to_map_over...);


Unfortunately, when I try to compile this (using clang++), I get the following error.



map.hpp:14:8: error: class template partial specialization contains template
parameters that cannot be deduced; this partial specialization will never
be used
[-Wunusable-partial-specialization]
struct Map
^~~
map.hpp:8:8: note: non-deducible template parameter 'ReturnType'
class ReturnType,
^
map.hpp:9:8: note: non-deducible template parameter 'Item'
class Item,
^
map.hpp:10:11: note: non-deducible template parameter 'ArgumentTypes'
class... ArgumentTypes,
^
map.hpp:11:7: note: non-deducible template parameter 'f'
auto f,
^
map.hpp:12:11: note: non-deducible template parameter 'Items'
class... Items
^
1 error generated.


Now, I wouldn't be surprised if it doesn't like the fact that ArgumentTypes... shows up twice in my specializations, though it isn't saying so directly.



What exactly is going wrong, and how might I build my map primitive in a way that avoid this? I don't want to store copies or references to any of the arguments, because that shouldn't be necessary. If I were manually writing a template that specialized the function and parameter types, I wouldn't need to store anything. This rules out tuple wrappers as an option.



EDIT: Added usage information, as requested.



EDIT: Fixed overzealous use of rvalue reference qualifiers, to avoid confusion.










share|improve this question

























  • Notice that you use rvalue-references and not forwarding references.

    – Jarod42
    Nov 23 '18 at 11:33











  • @Jarod42: Oops. That is basically a typo. I've fixed that now.

    – Zistack
    Nov 23 '18 at 19:23


















0















I'm trying to define a sort of template 'map' primitive (as in map-reduce). The idea is that I want to apply a function to every item of a template parameter pack. The function can be any callable object. It can return any type (though the return type will be ignored), and it can take additional arguments on top of the item in question.



The tricky part is that I effectively have two parameter packs that I need to deal with. They'll initially be packed together, but I want to split them using template specialization. What follows is my attempt at doing this.



In case it isn't obvious (due to the auto keyword in the template parameter list), this is using C++17.



#include <utility>

template <class Signature, auto f, class... ArgsAndItems>
struct Map;

template
<
class ReturnType,
class Item,
class... ArgumentTypes,
auto f,
class... Items
>
struct Map
<
ReturnType (Item, ArgumentTypes...),
f,
ArgumentTypes...,
Item,
Items...
>
{
static void
function (ArgumentTypes &&... arguments, Item && item, Items &&... items);
};

template <class ReturnType, class Item, class... ArgumentTypes, auto f>
struct Map<ReturnType (Item, ArgumentTypes...), f, ArgumentTypes...>
{
static void
function (ArgumentTypes &&... arguments);
};

template
<
class ReturnType,
class Item,
class... ArgumentTypes,
auto f,
class... Items
>
void
Map
<
ReturnType (Item, ArgumentTypes...),
f,
ArgumentTypes...,
Item,
Items...
>::function (ArgumentTypes &&... arguments, Item && item, Items &&... items)
{
f (std::forward<Item> (item), std::forward<ArgumentTypes> (arguments)...);
Map
<
ReturnType (Item, ArgumentTypes ...),
f,
ArgumentTypes...,
Items...
>::function
(
std::forward<ArgumentTypes> (arguments)...,
std::forward<Items> (items)...
);
}

template <class ReturnType, class Item, class... ArgumentTypes, auto f>
void
Map
<
ReturnType (Item, ArgumentTypes...),
f,
ArgumentTypes...
>::function (ArgumentTypes &&... arguments)
{
}


The idea is to have a wrapper that looks something like



template <auto f, class ... ArgsAndItems>
void
map (ArgsAndItems && ... args_and_items)
{
Map
<
decltype (decltype (f)::operator ()),
f,
ArgsAndItems...
>::function (std::forward <ArgsAndItems> (args_and_items) ...);
}


Which I would then use as



map <foo> (args_for_foo..., items_to_map_over...);


Unfortunately, when I try to compile this (using clang++), I get the following error.



map.hpp:14:8: error: class template partial specialization contains template
parameters that cannot be deduced; this partial specialization will never
be used
[-Wunusable-partial-specialization]
struct Map
^~~
map.hpp:8:8: note: non-deducible template parameter 'ReturnType'
class ReturnType,
^
map.hpp:9:8: note: non-deducible template parameter 'Item'
class Item,
^
map.hpp:10:11: note: non-deducible template parameter 'ArgumentTypes'
class... ArgumentTypes,
^
map.hpp:11:7: note: non-deducible template parameter 'f'
auto f,
^
map.hpp:12:11: note: non-deducible template parameter 'Items'
class... Items
^
1 error generated.


Now, I wouldn't be surprised if it doesn't like the fact that ArgumentTypes... shows up twice in my specializations, though it isn't saying so directly.



What exactly is going wrong, and how might I build my map primitive in a way that avoid this? I don't want to store copies or references to any of the arguments, because that shouldn't be necessary. If I were manually writing a template that specialized the function and parameter types, I wouldn't need to store anything. This rules out tuple wrappers as an option.



EDIT: Added usage information, as requested.



EDIT: Fixed overzealous use of rvalue reference qualifiers, to avoid confusion.










share|improve this question

























  • Notice that you use rvalue-references and not forwarding references.

    – Jarod42
    Nov 23 '18 at 11:33











  • @Jarod42: Oops. That is basically a typo. I've fixed that now.

    – Zistack
    Nov 23 '18 at 19:23














0












0








0








I'm trying to define a sort of template 'map' primitive (as in map-reduce). The idea is that I want to apply a function to every item of a template parameter pack. The function can be any callable object. It can return any type (though the return type will be ignored), and it can take additional arguments on top of the item in question.



The tricky part is that I effectively have two parameter packs that I need to deal with. They'll initially be packed together, but I want to split them using template specialization. What follows is my attempt at doing this.



In case it isn't obvious (due to the auto keyword in the template parameter list), this is using C++17.



#include <utility>

template <class Signature, auto f, class... ArgsAndItems>
struct Map;

template
<
class ReturnType,
class Item,
class... ArgumentTypes,
auto f,
class... Items
>
struct Map
<
ReturnType (Item, ArgumentTypes...),
f,
ArgumentTypes...,
Item,
Items...
>
{
static void
function (ArgumentTypes &&... arguments, Item && item, Items &&... items);
};

template <class ReturnType, class Item, class... ArgumentTypes, auto f>
struct Map<ReturnType (Item, ArgumentTypes...), f, ArgumentTypes...>
{
static void
function (ArgumentTypes &&... arguments);
};

template
<
class ReturnType,
class Item,
class... ArgumentTypes,
auto f,
class... Items
>
void
Map
<
ReturnType (Item, ArgumentTypes...),
f,
ArgumentTypes...,
Item,
Items...
>::function (ArgumentTypes &&... arguments, Item && item, Items &&... items)
{
f (std::forward<Item> (item), std::forward<ArgumentTypes> (arguments)...);
Map
<
ReturnType (Item, ArgumentTypes ...),
f,
ArgumentTypes...,
Items...
>::function
(
std::forward<ArgumentTypes> (arguments)...,
std::forward<Items> (items)...
);
}

template <class ReturnType, class Item, class... ArgumentTypes, auto f>
void
Map
<
ReturnType (Item, ArgumentTypes...),
f,
ArgumentTypes...
>::function (ArgumentTypes &&... arguments)
{
}


The idea is to have a wrapper that looks something like



template <auto f, class ... ArgsAndItems>
void
map (ArgsAndItems && ... args_and_items)
{
Map
<
decltype (decltype (f)::operator ()),
f,
ArgsAndItems...
>::function (std::forward <ArgsAndItems> (args_and_items) ...);
}


Which I would then use as



map <foo> (args_for_foo..., items_to_map_over...);


Unfortunately, when I try to compile this (using clang++), I get the following error.



map.hpp:14:8: error: class template partial specialization contains template
parameters that cannot be deduced; this partial specialization will never
be used
[-Wunusable-partial-specialization]
struct Map
^~~
map.hpp:8:8: note: non-deducible template parameter 'ReturnType'
class ReturnType,
^
map.hpp:9:8: note: non-deducible template parameter 'Item'
class Item,
^
map.hpp:10:11: note: non-deducible template parameter 'ArgumentTypes'
class... ArgumentTypes,
^
map.hpp:11:7: note: non-deducible template parameter 'f'
auto f,
^
map.hpp:12:11: note: non-deducible template parameter 'Items'
class... Items
^
1 error generated.


Now, I wouldn't be surprised if it doesn't like the fact that ArgumentTypes... shows up twice in my specializations, though it isn't saying so directly.



What exactly is going wrong, and how might I build my map primitive in a way that avoid this? I don't want to store copies or references to any of the arguments, because that shouldn't be necessary. If I were manually writing a template that specialized the function and parameter types, I wouldn't need to store anything. This rules out tuple wrappers as an option.



EDIT: Added usage information, as requested.



EDIT: Fixed overzealous use of rvalue reference qualifiers, to avoid confusion.










share|improve this question
















I'm trying to define a sort of template 'map' primitive (as in map-reduce). The idea is that I want to apply a function to every item of a template parameter pack. The function can be any callable object. It can return any type (though the return type will be ignored), and it can take additional arguments on top of the item in question.



The tricky part is that I effectively have two parameter packs that I need to deal with. They'll initially be packed together, but I want to split them using template specialization. What follows is my attempt at doing this.



In case it isn't obvious (due to the auto keyword in the template parameter list), this is using C++17.



#include <utility>

template <class Signature, auto f, class... ArgsAndItems>
struct Map;

template
<
class ReturnType,
class Item,
class... ArgumentTypes,
auto f,
class... Items
>
struct Map
<
ReturnType (Item, ArgumentTypes...),
f,
ArgumentTypes...,
Item,
Items...
>
{
static void
function (ArgumentTypes &&... arguments, Item && item, Items &&... items);
};

template <class ReturnType, class Item, class... ArgumentTypes, auto f>
struct Map<ReturnType (Item, ArgumentTypes...), f, ArgumentTypes...>
{
static void
function (ArgumentTypes &&... arguments);
};

template
<
class ReturnType,
class Item,
class... ArgumentTypes,
auto f,
class... Items
>
void
Map
<
ReturnType (Item, ArgumentTypes...),
f,
ArgumentTypes...,
Item,
Items...
>::function (ArgumentTypes &&... arguments, Item && item, Items &&... items)
{
f (std::forward<Item> (item), std::forward<ArgumentTypes> (arguments)...);
Map
<
ReturnType (Item, ArgumentTypes ...),
f,
ArgumentTypes...,
Items...
>::function
(
std::forward<ArgumentTypes> (arguments)...,
std::forward<Items> (items)...
);
}

template <class ReturnType, class Item, class... ArgumentTypes, auto f>
void
Map
<
ReturnType (Item, ArgumentTypes...),
f,
ArgumentTypes...
>::function (ArgumentTypes &&... arguments)
{
}


The idea is to have a wrapper that looks something like



template <auto f, class ... ArgsAndItems>
void
map (ArgsAndItems && ... args_and_items)
{
Map
<
decltype (decltype (f)::operator ()),
f,
ArgsAndItems...
>::function (std::forward <ArgsAndItems> (args_and_items) ...);
}


Which I would then use as



map <foo> (args_for_foo..., items_to_map_over...);


Unfortunately, when I try to compile this (using clang++), I get the following error.



map.hpp:14:8: error: class template partial specialization contains template
parameters that cannot be deduced; this partial specialization will never
be used
[-Wunusable-partial-specialization]
struct Map
^~~
map.hpp:8:8: note: non-deducible template parameter 'ReturnType'
class ReturnType,
^
map.hpp:9:8: note: non-deducible template parameter 'Item'
class Item,
^
map.hpp:10:11: note: non-deducible template parameter 'ArgumentTypes'
class... ArgumentTypes,
^
map.hpp:11:7: note: non-deducible template parameter 'f'
auto f,
^
map.hpp:12:11: note: non-deducible template parameter 'Items'
class... Items
^
1 error generated.


Now, I wouldn't be surprised if it doesn't like the fact that ArgumentTypes... shows up twice in my specializations, though it isn't saying so directly.



What exactly is going wrong, and how might I build my map primitive in a way that avoid this? I don't want to store copies or references to any of the arguments, because that shouldn't be necessary. If I were manually writing a template that specialized the function and parameter types, I wouldn't need to store anything. This rules out tuple wrappers as an option.



EDIT: Added usage information, as requested.



EDIT: Fixed overzealous use of rvalue reference qualifiers, to avoid confusion.







c++ c++17 variadic-templates template-specialization partial-specialization






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 23 '18 at 19:22







Zistack

















asked Nov 22 '18 at 20:50









ZistackZistack

386210




386210













  • Notice that you use rvalue-references and not forwarding references.

    – Jarod42
    Nov 23 '18 at 11:33











  • @Jarod42: Oops. That is basically a typo. I've fixed that now.

    – Zistack
    Nov 23 '18 at 19:23



















  • Notice that you use rvalue-references and not forwarding references.

    – Jarod42
    Nov 23 '18 at 11:33











  • @Jarod42: Oops. That is basically a typo. I've fixed that now.

    – Zistack
    Nov 23 '18 at 19:23

















Notice that you use rvalue-references and not forwarding references.

– Jarod42
Nov 23 '18 at 11:33





Notice that you use rvalue-references and not forwarding references.

– Jarod42
Nov 23 '18 at 11:33













@Jarod42: Oops. That is basically a typo. I've fixed that now.

– Zistack
Nov 23 '18 at 19:23





@Jarod42: Oops. That is basically a typo. I've fixed that now.

– Zistack
Nov 23 '18 at 19:23












1 Answer
1






active

oldest

votes


















1















What exactly is going wrong, [...]




There are several issues so it may be easier to start with a simple base example that works (no perfect forwarding).




[...] and how might I build my map primitive in a way that avoid this?




You can separate the parameter packs:




  • argument types are passed as template arguments for Map

  • item types are passed as template arguments for Map::function


Here is a working example without perfect forwarding. It is not complete regarding the deduction of the argument types because of possible cv-qualifiers and ref-qualifiers.



#include <iostream>

template<class F, class... Args>
struct Map {
template<class... Items>
static void function(Args... args, Items... items) {
static constexpr auto f = F{};

// here comes a fold expression
// see https://en.cppreference.com/w/cpp/language/fold

( f(items, args...), ...); // "fold over comma operator"
}
};

////////////////////////////////////////////////////////////////////////////////

template<class F, class Ret, class Item, class... Args, class... ArgsItems>
void map_impl(Ret(F::*)(Item, Args...) const, ArgsItems... args_items) {
Map<F, Args...>::function(args_items...);
}

template<class F, class... ArgsItems>
void map(ArgsItems... args_items) {
map_impl<F>(&F::operator(), args_items...);
}

////////////////////////////////////////////////////////////////////////////////

struct print_x_m_plus_n {
void operator()(int x, int m, int n) const {
int y = x * m + n;
std::cout << y << std::endl;
}
};

int main() {
constexpr int m = 2;
constexpr int n = 1;

map<print_x_m_plus_n>(m, n, 0, 1, 2);
}


Output:



1
3
5





share|improve this answer
























  • I omitted the perfect forwarding because I am not sure that it is allowed for the function arguments (m and n in my example): Imagine there are some ressources that are moved when the function is called for the first item. Where should the following function calls move from?

    – Julius
    Nov 23 '18 at 8:57













  • I would tend to allow it for the function arguments. It is the user's problem if they decide to move arguments in a function that they're about to call repeatedly. BTW, thanks for pointing out the fold expression trick. I only just started using the C++17 features, so I'm still learning what all is available.

    – Zistack
    Nov 23 '18 at 20:21














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
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53437838%2fsplit-variadic-parameter-pack-using-template-specialization%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1















What exactly is going wrong, [...]




There are several issues so it may be easier to start with a simple base example that works (no perfect forwarding).




[...] and how might I build my map primitive in a way that avoid this?




You can separate the parameter packs:




  • argument types are passed as template arguments for Map

  • item types are passed as template arguments for Map::function


Here is a working example without perfect forwarding. It is not complete regarding the deduction of the argument types because of possible cv-qualifiers and ref-qualifiers.



#include <iostream>

template<class F, class... Args>
struct Map {
template<class... Items>
static void function(Args... args, Items... items) {
static constexpr auto f = F{};

// here comes a fold expression
// see https://en.cppreference.com/w/cpp/language/fold

( f(items, args...), ...); // "fold over comma operator"
}
};

////////////////////////////////////////////////////////////////////////////////

template<class F, class Ret, class Item, class... Args, class... ArgsItems>
void map_impl(Ret(F::*)(Item, Args...) const, ArgsItems... args_items) {
Map<F, Args...>::function(args_items...);
}

template<class F, class... ArgsItems>
void map(ArgsItems... args_items) {
map_impl<F>(&F::operator(), args_items...);
}

////////////////////////////////////////////////////////////////////////////////

struct print_x_m_plus_n {
void operator()(int x, int m, int n) const {
int y = x * m + n;
std::cout << y << std::endl;
}
};

int main() {
constexpr int m = 2;
constexpr int n = 1;

map<print_x_m_plus_n>(m, n, 0, 1, 2);
}


Output:



1
3
5





share|improve this answer
























  • I omitted the perfect forwarding because I am not sure that it is allowed for the function arguments (m and n in my example): Imagine there are some ressources that are moved when the function is called for the first item. Where should the following function calls move from?

    – Julius
    Nov 23 '18 at 8:57













  • I would tend to allow it for the function arguments. It is the user's problem if they decide to move arguments in a function that they're about to call repeatedly. BTW, thanks for pointing out the fold expression trick. I only just started using the C++17 features, so I'm still learning what all is available.

    – Zistack
    Nov 23 '18 at 20:21


















1















What exactly is going wrong, [...]




There are several issues so it may be easier to start with a simple base example that works (no perfect forwarding).




[...] and how might I build my map primitive in a way that avoid this?




You can separate the parameter packs:




  • argument types are passed as template arguments for Map

  • item types are passed as template arguments for Map::function


Here is a working example without perfect forwarding. It is not complete regarding the deduction of the argument types because of possible cv-qualifiers and ref-qualifiers.



#include <iostream>

template<class F, class... Args>
struct Map {
template<class... Items>
static void function(Args... args, Items... items) {
static constexpr auto f = F{};

// here comes a fold expression
// see https://en.cppreference.com/w/cpp/language/fold

( f(items, args...), ...); // "fold over comma operator"
}
};

////////////////////////////////////////////////////////////////////////////////

template<class F, class Ret, class Item, class... Args, class... ArgsItems>
void map_impl(Ret(F::*)(Item, Args...) const, ArgsItems... args_items) {
Map<F, Args...>::function(args_items...);
}

template<class F, class... ArgsItems>
void map(ArgsItems... args_items) {
map_impl<F>(&F::operator(), args_items...);
}

////////////////////////////////////////////////////////////////////////////////

struct print_x_m_plus_n {
void operator()(int x, int m, int n) const {
int y = x * m + n;
std::cout << y << std::endl;
}
};

int main() {
constexpr int m = 2;
constexpr int n = 1;

map<print_x_m_plus_n>(m, n, 0, 1, 2);
}


Output:



1
3
5





share|improve this answer
























  • I omitted the perfect forwarding because I am not sure that it is allowed for the function arguments (m and n in my example): Imagine there are some ressources that are moved when the function is called for the first item. Where should the following function calls move from?

    – Julius
    Nov 23 '18 at 8:57













  • I would tend to allow it for the function arguments. It is the user's problem if they decide to move arguments in a function that they're about to call repeatedly. BTW, thanks for pointing out the fold expression trick. I only just started using the C++17 features, so I'm still learning what all is available.

    – Zistack
    Nov 23 '18 at 20:21
















1












1








1








What exactly is going wrong, [...]




There are several issues so it may be easier to start with a simple base example that works (no perfect forwarding).




[...] and how might I build my map primitive in a way that avoid this?




You can separate the parameter packs:




  • argument types are passed as template arguments for Map

  • item types are passed as template arguments for Map::function


Here is a working example without perfect forwarding. It is not complete regarding the deduction of the argument types because of possible cv-qualifiers and ref-qualifiers.



#include <iostream>

template<class F, class... Args>
struct Map {
template<class... Items>
static void function(Args... args, Items... items) {
static constexpr auto f = F{};

// here comes a fold expression
// see https://en.cppreference.com/w/cpp/language/fold

( f(items, args...), ...); // "fold over comma operator"
}
};

////////////////////////////////////////////////////////////////////////////////

template<class F, class Ret, class Item, class... Args, class... ArgsItems>
void map_impl(Ret(F::*)(Item, Args...) const, ArgsItems... args_items) {
Map<F, Args...>::function(args_items...);
}

template<class F, class... ArgsItems>
void map(ArgsItems... args_items) {
map_impl<F>(&F::operator(), args_items...);
}

////////////////////////////////////////////////////////////////////////////////

struct print_x_m_plus_n {
void operator()(int x, int m, int n) const {
int y = x * m + n;
std::cout << y << std::endl;
}
};

int main() {
constexpr int m = 2;
constexpr int n = 1;

map<print_x_m_plus_n>(m, n, 0, 1, 2);
}


Output:



1
3
5





share|improve this answer














What exactly is going wrong, [...]




There are several issues so it may be easier to start with a simple base example that works (no perfect forwarding).




[...] and how might I build my map primitive in a way that avoid this?




You can separate the parameter packs:




  • argument types are passed as template arguments for Map

  • item types are passed as template arguments for Map::function


Here is a working example without perfect forwarding. It is not complete regarding the deduction of the argument types because of possible cv-qualifiers and ref-qualifiers.



#include <iostream>

template<class F, class... Args>
struct Map {
template<class... Items>
static void function(Args... args, Items... items) {
static constexpr auto f = F{};

// here comes a fold expression
// see https://en.cppreference.com/w/cpp/language/fold

( f(items, args...), ...); // "fold over comma operator"
}
};

////////////////////////////////////////////////////////////////////////////////

template<class F, class Ret, class Item, class... Args, class... ArgsItems>
void map_impl(Ret(F::*)(Item, Args...) const, ArgsItems... args_items) {
Map<F, Args...>::function(args_items...);
}

template<class F, class... ArgsItems>
void map(ArgsItems... args_items) {
map_impl<F>(&F::operator(), args_items...);
}

////////////////////////////////////////////////////////////////////////////////

struct print_x_m_plus_n {
void operator()(int x, int m, int n) const {
int y = x * m + n;
std::cout << y << std::endl;
}
};

int main() {
constexpr int m = 2;
constexpr int n = 1;

map<print_x_m_plus_n>(m, n, 0, 1, 2);
}


Output:



1
3
5






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 23 '18 at 8:50









JuliusJulius

1,269613




1,269613













  • I omitted the perfect forwarding because I am not sure that it is allowed for the function arguments (m and n in my example): Imagine there are some ressources that are moved when the function is called for the first item. Where should the following function calls move from?

    – Julius
    Nov 23 '18 at 8:57













  • I would tend to allow it for the function arguments. It is the user's problem if they decide to move arguments in a function that they're about to call repeatedly. BTW, thanks for pointing out the fold expression trick. I only just started using the C++17 features, so I'm still learning what all is available.

    – Zistack
    Nov 23 '18 at 20:21





















  • I omitted the perfect forwarding because I am not sure that it is allowed for the function arguments (m and n in my example): Imagine there are some ressources that are moved when the function is called for the first item. Where should the following function calls move from?

    – Julius
    Nov 23 '18 at 8:57













  • I would tend to allow it for the function arguments. It is the user's problem if they decide to move arguments in a function that they're about to call repeatedly. BTW, thanks for pointing out the fold expression trick. I only just started using the C++17 features, so I'm still learning what all is available.

    – Zistack
    Nov 23 '18 at 20:21



















I omitted the perfect forwarding because I am not sure that it is allowed for the function arguments (m and n in my example): Imagine there are some ressources that are moved when the function is called for the first item. Where should the following function calls move from?

– Julius
Nov 23 '18 at 8:57







I omitted the perfect forwarding because I am not sure that it is allowed for the function arguments (m and n in my example): Imagine there are some ressources that are moved when the function is called for the first item. Where should the following function calls move from?

– Julius
Nov 23 '18 at 8:57















I would tend to allow it for the function arguments. It is the user's problem if they decide to move arguments in a function that they're about to call repeatedly. BTW, thanks for pointing out the fold expression trick. I only just started using the C++17 features, so I'm still learning what all is available.

– Zistack
Nov 23 '18 at 20:21







I would tend to allow it for the function arguments. It is the user's problem if they decide to move arguments in a function that they're about to call repeatedly. BTW, thanks for pointing out the fold expression trick. I only just started using the C++17 features, so I'm still learning what all is available.

– Zistack
Nov 23 '18 at 20:21






















draft saved

draft discarded




















































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.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53437838%2fsplit-variadic-parameter-pack-using-template-specialization%23new-answer', 'question_page');
}
);

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







這個網誌中的熱門文章

Tangent Lines Diagram Along Smooth Curve

Yusuf al-Mu'taman ibn Hud

Zucchini