C++, pass two parameter packs to constructor





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







4















I have the following problem. I have a class (mixin), that has two template bases.



template <typename T>
class Id
{
using result = T;
};

template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <typename... Args1, typename... Args2>
SeveralPrinters(dummy, helper<Args1...>, helper<Args2...>,
typename Id<Args1>::result... args1,
typename Id<Args2>::result... args2)
: Printer1(std::forward<Args1>(args1)..., std::forward<Args2>(args2)...)
{}
public:
template <typename... Args, typename =
std::enable_if_t<!contains<dummy, Args...>::result>>
SeveralPrinters(Args&&... args)
: SeveralPrinters(dummy(), typename Printer1::ArgsCtor(),
typename Printer2::ArgsCtor(), std::forward<Args>(args)...)
{
}
};


All names of classes are fictitious. So, imagine its first base accepts int as constructor argument and second base accepts double. What I want to do is to be able to call constructor of SeveralPrinters like SeveralPrinters(1, 2.). The problem here, is that Args1 and Args2 are deduced not from helper structure, but from args, passed after helper structure. As you can see, I tried to wrap template arguments into Id structure, and that didn't help. I know, it is called smth like Non-deduced contexts, but I couldn't manage to make it work. Can anyone help with it (if it possible), and maybe explain a little bit more on this topic (why it doesn't work now).
Example of base classes:



class BasicPrinter1
{
public:
BasicPrinter1(int)
{}
void f()
{
}
using ArgsCtor = helper<int>;
};

class BasicPrinter2
{
public:
BasicPrinter2(int*)
{}
void g()
{
}
using ArgsCtor = helper<int*>;
};









share|improve this question























  • You cannot deduce two or more parameter packs from a single parameter list. End of story. You have to choose a different calling sequence. Perhaps a pair of tuples.

    – Sam Varshavchik
    Nov 25 '18 at 12:06






  • 3





    @SamVarshavchik OP is using a helper struct to deduce them

    – Piotr Skotnicki
    Nov 25 '18 at 12:06


















4















I have the following problem. I have a class (mixin), that has two template bases.



template <typename T>
class Id
{
using result = T;
};

template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <typename... Args1, typename... Args2>
SeveralPrinters(dummy, helper<Args1...>, helper<Args2...>,
typename Id<Args1>::result... args1,
typename Id<Args2>::result... args2)
: Printer1(std::forward<Args1>(args1)..., std::forward<Args2>(args2)...)
{}
public:
template <typename... Args, typename =
std::enable_if_t<!contains<dummy, Args...>::result>>
SeveralPrinters(Args&&... args)
: SeveralPrinters(dummy(), typename Printer1::ArgsCtor(),
typename Printer2::ArgsCtor(), std::forward<Args>(args)...)
{
}
};


All names of classes are fictitious. So, imagine its first base accepts int as constructor argument and second base accepts double. What I want to do is to be able to call constructor of SeveralPrinters like SeveralPrinters(1, 2.). The problem here, is that Args1 and Args2 are deduced not from helper structure, but from args, passed after helper structure. As you can see, I tried to wrap template arguments into Id structure, and that didn't help. I know, it is called smth like Non-deduced contexts, but I couldn't manage to make it work. Can anyone help with it (if it possible), and maybe explain a little bit more on this topic (why it doesn't work now).
Example of base classes:



class BasicPrinter1
{
public:
BasicPrinter1(int)
{}
void f()
{
}
using ArgsCtor = helper<int>;
};

class BasicPrinter2
{
public:
BasicPrinter2(int*)
{}
void g()
{
}
using ArgsCtor = helper<int*>;
};









share|improve this question























  • You cannot deduce two or more parameter packs from a single parameter list. End of story. You have to choose a different calling sequence. Perhaps a pair of tuples.

    – Sam Varshavchik
    Nov 25 '18 at 12:06






  • 3





    @SamVarshavchik OP is using a helper struct to deduce them

    – Piotr Skotnicki
    Nov 25 '18 at 12:06














4












4








4








I have the following problem. I have a class (mixin), that has two template bases.



template <typename T>
class Id
{
using result = T;
};

template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <typename... Args1, typename... Args2>
SeveralPrinters(dummy, helper<Args1...>, helper<Args2...>,
typename Id<Args1>::result... args1,
typename Id<Args2>::result... args2)
: Printer1(std::forward<Args1>(args1)..., std::forward<Args2>(args2)...)
{}
public:
template <typename... Args, typename =
std::enable_if_t<!contains<dummy, Args...>::result>>
SeveralPrinters(Args&&... args)
: SeveralPrinters(dummy(), typename Printer1::ArgsCtor(),
typename Printer2::ArgsCtor(), std::forward<Args>(args)...)
{
}
};


All names of classes are fictitious. So, imagine its first base accepts int as constructor argument and second base accepts double. What I want to do is to be able to call constructor of SeveralPrinters like SeveralPrinters(1, 2.). The problem here, is that Args1 and Args2 are deduced not from helper structure, but from args, passed after helper structure. As you can see, I tried to wrap template arguments into Id structure, and that didn't help. I know, it is called smth like Non-deduced contexts, but I couldn't manage to make it work. Can anyone help with it (if it possible), and maybe explain a little bit more on this topic (why it doesn't work now).
Example of base classes:



class BasicPrinter1
{
public:
BasicPrinter1(int)
{}
void f()
{
}
using ArgsCtor = helper<int>;
};

class BasicPrinter2
{
public:
BasicPrinter2(int*)
{}
void g()
{
}
using ArgsCtor = helper<int*>;
};









share|improve this question














I have the following problem. I have a class (mixin), that has two template bases.



template <typename T>
class Id
{
using result = T;
};

template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <typename... Args1, typename... Args2>
SeveralPrinters(dummy, helper<Args1...>, helper<Args2...>,
typename Id<Args1>::result... args1,
typename Id<Args2>::result... args2)
: Printer1(std::forward<Args1>(args1)..., std::forward<Args2>(args2)...)
{}
public:
template <typename... Args, typename =
std::enable_if_t<!contains<dummy, Args...>::result>>
SeveralPrinters(Args&&... args)
: SeveralPrinters(dummy(), typename Printer1::ArgsCtor(),
typename Printer2::ArgsCtor(), std::forward<Args>(args)...)
{
}
};


All names of classes are fictitious. So, imagine its first base accepts int as constructor argument and second base accepts double. What I want to do is to be able to call constructor of SeveralPrinters like SeveralPrinters(1, 2.). The problem here, is that Args1 and Args2 are deduced not from helper structure, but from args, passed after helper structure. As you can see, I tried to wrap template arguments into Id structure, and that didn't help. I know, it is called smth like Non-deduced contexts, but I couldn't manage to make it work. Can anyone help with it (if it possible), and maybe explain a little bit more on this topic (why it doesn't work now).
Example of base classes:



class BasicPrinter1
{
public:
BasicPrinter1(int)
{}
void f()
{
}
using ArgsCtor = helper<int>;
};

class BasicPrinter2
{
public:
BasicPrinter2(int*)
{}
void g()
{
}
using ArgsCtor = helper<int*>;
};






c++ templates mixins






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 25 '18 at 11:51









Nikita VorobyevNikita Vorobyev

1108




1108













  • You cannot deduce two or more parameter packs from a single parameter list. End of story. You have to choose a different calling sequence. Perhaps a pair of tuples.

    – Sam Varshavchik
    Nov 25 '18 at 12:06






  • 3





    @SamVarshavchik OP is using a helper struct to deduce them

    – Piotr Skotnicki
    Nov 25 '18 at 12:06



















  • You cannot deduce two or more parameter packs from a single parameter list. End of story. You have to choose a different calling sequence. Perhaps a pair of tuples.

    – Sam Varshavchik
    Nov 25 '18 at 12:06






  • 3





    @SamVarshavchik OP is using a helper struct to deduce them

    – Piotr Skotnicki
    Nov 25 '18 at 12:06

















You cannot deduce two or more parameter packs from a single parameter list. End of story. You have to choose a different calling sequence. Perhaps a pair of tuples.

– Sam Varshavchik
Nov 25 '18 at 12:06





You cannot deduce two or more parameter packs from a single parameter list. End of story. You have to choose a different calling sequence. Perhaps a pair of tuples.

– Sam Varshavchik
Nov 25 '18 at 12:06




3




3





@SamVarshavchik OP is using a helper struct to deduce them

– Piotr Skotnicki
Nov 25 '18 at 12:06





@SamVarshavchik OP is using a helper struct to deduce them

– Piotr Skotnicki
Nov 25 '18 at 12:06












1 Answer
1






active

oldest

votes


















3














It doesn't work mainly because the alias result in Id is private (default accessibility for classes), and so not accessible from the private constructor of SeveralPrinters, leading to a substitution failure (typename Id<Args1>::result) with no other viable candidate constructor to call. There were also a couple of typos in your code.



template <typename T>
struct Id
{
using result = T;
};

template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <typename... Args1, typename... Args2>
SeveralPrinters(dummy, helper<Args1...>, helper<Args2...>
, typename Id<Args1>::result... args1
, typename Id<Args2>::result... args2)
: Printer1(std::forward<Args1>(args1)...)
, Printer2(std::forward<Args2>(args2)...)
{}

public:
template <typename... Args>
SeveralPrinters(Args&&... args)
: SeveralPrinters(dummy{}
, typename Printer1::ArgsCtor{}
, typename Printer2::ArgsCtor{}
, std::forward<Args>(args)...)
{}
};


DEMO





In order to perfectly-forward the arguments to base classes, you should instead declare the number of parameters (ArgsCount) and use the below implementation:



template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <std::size_t... Is
, std::size_t... Js
, typename... Args>
SeveralPrinters(std::index_sequence<Is...>
, std::index_sequence<Js...>
, std::tuple<Args...>&& t)
: Printer1(std::get<Is>(std::move(t))...)
, Printer2(std::get<sizeof...(Is) + Js>(std::move(t))...)
{}

public:
SeveralPrinters() = default;
SeveralPrinters(const SeveralPrinters&) = default;
SeveralPrinters(SeveralPrinters& rhs)
: SeveralPrinters(static_cast<const SeveralPrinters&>(rhs))
{}

template <typename... Args>
SeveralPrinters(Args&&... args)
: SeveralPrinters(std::make_index_sequence<Printer1::ArgsCount>{}
, std::make_index_sequence<Printer2::ArgsCount>{}
, std::forward_as_tuple(std::forward<Args>(args)...))
{}
};

struct BasicPrinter1
{
BasicPrinter1(int) {}
static constexpr ArgsCount = 1;
};

struct BasicPrinter2
{
BasicPrinter2(int*, char&) {}
static constexpr ArgsCount = 2;
};


DEMO 2



Also notice how I'm protecting the copy-constructor from being overshadowed by the forwarding-references constructor.






share|improve this answer


























  • I suppose also universal reference for args1 and args2 in first contructor

    – max66
    Nov 25 '18 at 12:33











  • What a shame:) Thanks! Compiler errors weren't even close to pointing out, that the problem because of private using. Also, what seems interesting, this code causes clang to infinitely compile and eat all my RAM, although g++ compiles it without problems. And, if I add enable_if, clang will still be saying, that Args1 is empty, as if there was no Id structure.

    – Nikita Vorobyev
    Nov 25 '18 at 12:37













  • @NikitaVorobyev I removed your contains predicate, and in such a case it may lead to endless recursive calls, because forwarding references generate exact matches.

    – Piotr Skotnicki
    Nov 25 '18 at 12:38











  • @max66 perfect forwarding in this case would require more effort, since Args1 and Args2 cannot be forwarding references (though it is possible to optimize this implementation, like e.g., forwarding the arguments as a tuple and extracting exact amount of elements for each constructor call)

    – Piotr Skotnicki
    Nov 25 '18 at 12:40













  • @PiotrSkotnicki, this was the question, I wanted to ask. How is it possible to perfectly forward Args?

    – Nikita Vorobyev
    Nov 25 '18 at 12:42












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%2f53467137%2fc-pass-two-parameter-packs-to-constructor%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









3














It doesn't work mainly because the alias result in Id is private (default accessibility for classes), and so not accessible from the private constructor of SeveralPrinters, leading to a substitution failure (typename Id<Args1>::result) with no other viable candidate constructor to call. There were also a couple of typos in your code.



template <typename T>
struct Id
{
using result = T;
};

template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <typename... Args1, typename... Args2>
SeveralPrinters(dummy, helper<Args1...>, helper<Args2...>
, typename Id<Args1>::result... args1
, typename Id<Args2>::result... args2)
: Printer1(std::forward<Args1>(args1)...)
, Printer2(std::forward<Args2>(args2)...)
{}

public:
template <typename... Args>
SeveralPrinters(Args&&... args)
: SeveralPrinters(dummy{}
, typename Printer1::ArgsCtor{}
, typename Printer2::ArgsCtor{}
, std::forward<Args>(args)...)
{}
};


DEMO





In order to perfectly-forward the arguments to base classes, you should instead declare the number of parameters (ArgsCount) and use the below implementation:



template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <std::size_t... Is
, std::size_t... Js
, typename... Args>
SeveralPrinters(std::index_sequence<Is...>
, std::index_sequence<Js...>
, std::tuple<Args...>&& t)
: Printer1(std::get<Is>(std::move(t))...)
, Printer2(std::get<sizeof...(Is) + Js>(std::move(t))...)
{}

public:
SeveralPrinters() = default;
SeveralPrinters(const SeveralPrinters&) = default;
SeveralPrinters(SeveralPrinters& rhs)
: SeveralPrinters(static_cast<const SeveralPrinters&>(rhs))
{}

template <typename... Args>
SeveralPrinters(Args&&... args)
: SeveralPrinters(std::make_index_sequence<Printer1::ArgsCount>{}
, std::make_index_sequence<Printer2::ArgsCount>{}
, std::forward_as_tuple(std::forward<Args>(args)...))
{}
};

struct BasicPrinter1
{
BasicPrinter1(int) {}
static constexpr ArgsCount = 1;
};

struct BasicPrinter2
{
BasicPrinter2(int*, char&) {}
static constexpr ArgsCount = 2;
};


DEMO 2



Also notice how I'm protecting the copy-constructor from being overshadowed by the forwarding-references constructor.






share|improve this answer


























  • I suppose also universal reference for args1 and args2 in first contructor

    – max66
    Nov 25 '18 at 12:33











  • What a shame:) Thanks! Compiler errors weren't even close to pointing out, that the problem because of private using. Also, what seems interesting, this code causes clang to infinitely compile and eat all my RAM, although g++ compiles it without problems. And, if I add enable_if, clang will still be saying, that Args1 is empty, as if there was no Id structure.

    – Nikita Vorobyev
    Nov 25 '18 at 12:37













  • @NikitaVorobyev I removed your contains predicate, and in such a case it may lead to endless recursive calls, because forwarding references generate exact matches.

    – Piotr Skotnicki
    Nov 25 '18 at 12:38











  • @max66 perfect forwarding in this case would require more effort, since Args1 and Args2 cannot be forwarding references (though it is possible to optimize this implementation, like e.g., forwarding the arguments as a tuple and extracting exact amount of elements for each constructor call)

    – Piotr Skotnicki
    Nov 25 '18 at 12:40













  • @PiotrSkotnicki, this was the question, I wanted to ask. How is it possible to perfectly forward Args?

    – Nikita Vorobyev
    Nov 25 '18 at 12:42
















3














It doesn't work mainly because the alias result in Id is private (default accessibility for classes), and so not accessible from the private constructor of SeveralPrinters, leading to a substitution failure (typename Id<Args1>::result) with no other viable candidate constructor to call. There were also a couple of typos in your code.



template <typename T>
struct Id
{
using result = T;
};

template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <typename... Args1, typename... Args2>
SeveralPrinters(dummy, helper<Args1...>, helper<Args2...>
, typename Id<Args1>::result... args1
, typename Id<Args2>::result... args2)
: Printer1(std::forward<Args1>(args1)...)
, Printer2(std::forward<Args2>(args2)...)
{}

public:
template <typename... Args>
SeveralPrinters(Args&&... args)
: SeveralPrinters(dummy{}
, typename Printer1::ArgsCtor{}
, typename Printer2::ArgsCtor{}
, std::forward<Args>(args)...)
{}
};


DEMO





In order to perfectly-forward the arguments to base classes, you should instead declare the number of parameters (ArgsCount) and use the below implementation:



template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <std::size_t... Is
, std::size_t... Js
, typename... Args>
SeveralPrinters(std::index_sequence<Is...>
, std::index_sequence<Js...>
, std::tuple<Args...>&& t)
: Printer1(std::get<Is>(std::move(t))...)
, Printer2(std::get<sizeof...(Is) + Js>(std::move(t))...)
{}

public:
SeveralPrinters() = default;
SeveralPrinters(const SeveralPrinters&) = default;
SeveralPrinters(SeveralPrinters& rhs)
: SeveralPrinters(static_cast<const SeveralPrinters&>(rhs))
{}

template <typename... Args>
SeveralPrinters(Args&&... args)
: SeveralPrinters(std::make_index_sequence<Printer1::ArgsCount>{}
, std::make_index_sequence<Printer2::ArgsCount>{}
, std::forward_as_tuple(std::forward<Args>(args)...))
{}
};

struct BasicPrinter1
{
BasicPrinter1(int) {}
static constexpr ArgsCount = 1;
};

struct BasicPrinter2
{
BasicPrinter2(int*, char&) {}
static constexpr ArgsCount = 2;
};


DEMO 2



Also notice how I'm protecting the copy-constructor from being overshadowed by the forwarding-references constructor.






share|improve this answer


























  • I suppose also universal reference for args1 and args2 in first contructor

    – max66
    Nov 25 '18 at 12:33











  • What a shame:) Thanks! Compiler errors weren't even close to pointing out, that the problem because of private using. Also, what seems interesting, this code causes clang to infinitely compile and eat all my RAM, although g++ compiles it without problems. And, if I add enable_if, clang will still be saying, that Args1 is empty, as if there was no Id structure.

    – Nikita Vorobyev
    Nov 25 '18 at 12:37













  • @NikitaVorobyev I removed your contains predicate, and in such a case it may lead to endless recursive calls, because forwarding references generate exact matches.

    – Piotr Skotnicki
    Nov 25 '18 at 12:38











  • @max66 perfect forwarding in this case would require more effort, since Args1 and Args2 cannot be forwarding references (though it is possible to optimize this implementation, like e.g., forwarding the arguments as a tuple and extracting exact amount of elements for each constructor call)

    – Piotr Skotnicki
    Nov 25 '18 at 12:40













  • @PiotrSkotnicki, this was the question, I wanted to ask. How is it possible to perfectly forward Args?

    – Nikita Vorobyev
    Nov 25 '18 at 12:42














3












3








3







It doesn't work mainly because the alias result in Id is private (default accessibility for classes), and so not accessible from the private constructor of SeveralPrinters, leading to a substitution failure (typename Id<Args1>::result) with no other viable candidate constructor to call. There were also a couple of typos in your code.



template <typename T>
struct Id
{
using result = T;
};

template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <typename... Args1, typename... Args2>
SeveralPrinters(dummy, helper<Args1...>, helper<Args2...>
, typename Id<Args1>::result... args1
, typename Id<Args2>::result... args2)
: Printer1(std::forward<Args1>(args1)...)
, Printer2(std::forward<Args2>(args2)...)
{}

public:
template <typename... Args>
SeveralPrinters(Args&&... args)
: SeveralPrinters(dummy{}
, typename Printer1::ArgsCtor{}
, typename Printer2::ArgsCtor{}
, std::forward<Args>(args)...)
{}
};


DEMO





In order to perfectly-forward the arguments to base classes, you should instead declare the number of parameters (ArgsCount) and use the below implementation:



template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <std::size_t... Is
, std::size_t... Js
, typename... Args>
SeveralPrinters(std::index_sequence<Is...>
, std::index_sequence<Js...>
, std::tuple<Args...>&& t)
: Printer1(std::get<Is>(std::move(t))...)
, Printer2(std::get<sizeof...(Is) + Js>(std::move(t))...)
{}

public:
SeveralPrinters() = default;
SeveralPrinters(const SeveralPrinters&) = default;
SeveralPrinters(SeveralPrinters& rhs)
: SeveralPrinters(static_cast<const SeveralPrinters&>(rhs))
{}

template <typename... Args>
SeveralPrinters(Args&&... args)
: SeveralPrinters(std::make_index_sequence<Printer1::ArgsCount>{}
, std::make_index_sequence<Printer2::ArgsCount>{}
, std::forward_as_tuple(std::forward<Args>(args)...))
{}
};

struct BasicPrinter1
{
BasicPrinter1(int) {}
static constexpr ArgsCount = 1;
};

struct BasicPrinter2
{
BasicPrinter2(int*, char&) {}
static constexpr ArgsCount = 2;
};


DEMO 2



Also notice how I'm protecting the copy-constructor from being overshadowed by the forwarding-references constructor.






share|improve this answer















It doesn't work mainly because the alias result in Id is private (default accessibility for classes), and so not accessible from the private constructor of SeveralPrinters, leading to a substitution failure (typename Id<Args1>::result) with no other viable candidate constructor to call. There were also a couple of typos in your code.



template <typename T>
struct Id
{
using result = T;
};

template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <typename... Args1, typename... Args2>
SeveralPrinters(dummy, helper<Args1...>, helper<Args2...>
, typename Id<Args1>::result... args1
, typename Id<Args2>::result... args2)
: Printer1(std::forward<Args1>(args1)...)
, Printer2(std::forward<Args2>(args2)...)
{}

public:
template <typename... Args>
SeveralPrinters(Args&&... args)
: SeveralPrinters(dummy{}
, typename Printer1::ArgsCtor{}
, typename Printer2::ArgsCtor{}
, std::forward<Args>(args)...)
{}
};


DEMO





In order to perfectly-forward the arguments to base classes, you should instead declare the number of parameters (ArgsCount) and use the below implementation:



template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <std::size_t... Is
, std::size_t... Js
, typename... Args>
SeveralPrinters(std::index_sequence<Is...>
, std::index_sequence<Js...>
, std::tuple<Args...>&& t)
: Printer1(std::get<Is>(std::move(t))...)
, Printer2(std::get<sizeof...(Is) + Js>(std::move(t))...)
{}

public:
SeveralPrinters() = default;
SeveralPrinters(const SeveralPrinters&) = default;
SeveralPrinters(SeveralPrinters& rhs)
: SeveralPrinters(static_cast<const SeveralPrinters&>(rhs))
{}

template <typename... Args>
SeveralPrinters(Args&&... args)
: SeveralPrinters(std::make_index_sequence<Printer1::ArgsCount>{}
, std::make_index_sequence<Printer2::ArgsCount>{}
, std::forward_as_tuple(std::forward<Args>(args)...))
{}
};

struct BasicPrinter1
{
BasicPrinter1(int) {}
static constexpr ArgsCount = 1;
};

struct BasicPrinter2
{
BasicPrinter2(int*, char&) {}
static constexpr ArgsCount = 2;
};


DEMO 2



Also notice how I'm protecting the copy-constructor from being overshadowed by the forwarding-references constructor.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 25 '18 at 12:55

























answered Nov 25 '18 at 12:03









Piotr SkotnickiPiotr Skotnicki

35.2k473122




35.2k473122













  • I suppose also universal reference for args1 and args2 in first contructor

    – max66
    Nov 25 '18 at 12:33











  • What a shame:) Thanks! Compiler errors weren't even close to pointing out, that the problem because of private using. Also, what seems interesting, this code causes clang to infinitely compile and eat all my RAM, although g++ compiles it without problems. And, if I add enable_if, clang will still be saying, that Args1 is empty, as if there was no Id structure.

    – Nikita Vorobyev
    Nov 25 '18 at 12:37













  • @NikitaVorobyev I removed your contains predicate, and in such a case it may lead to endless recursive calls, because forwarding references generate exact matches.

    – Piotr Skotnicki
    Nov 25 '18 at 12:38











  • @max66 perfect forwarding in this case would require more effort, since Args1 and Args2 cannot be forwarding references (though it is possible to optimize this implementation, like e.g., forwarding the arguments as a tuple and extracting exact amount of elements for each constructor call)

    – Piotr Skotnicki
    Nov 25 '18 at 12:40













  • @PiotrSkotnicki, this was the question, I wanted to ask. How is it possible to perfectly forward Args?

    – Nikita Vorobyev
    Nov 25 '18 at 12:42



















  • I suppose also universal reference for args1 and args2 in first contructor

    – max66
    Nov 25 '18 at 12:33











  • What a shame:) Thanks! Compiler errors weren't even close to pointing out, that the problem because of private using. Also, what seems interesting, this code causes clang to infinitely compile and eat all my RAM, although g++ compiles it without problems. And, if I add enable_if, clang will still be saying, that Args1 is empty, as if there was no Id structure.

    – Nikita Vorobyev
    Nov 25 '18 at 12:37













  • @NikitaVorobyev I removed your contains predicate, and in such a case it may lead to endless recursive calls, because forwarding references generate exact matches.

    – Piotr Skotnicki
    Nov 25 '18 at 12:38











  • @max66 perfect forwarding in this case would require more effort, since Args1 and Args2 cannot be forwarding references (though it is possible to optimize this implementation, like e.g., forwarding the arguments as a tuple and extracting exact amount of elements for each constructor call)

    – Piotr Skotnicki
    Nov 25 '18 at 12:40













  • @PiotrSkotnicki, this was the question, I wanted to ask. How is it possible to perfectly forward Args?

    – Nikita Vorobyev
    Nov 25 '18 at 12:42

















I suppose also universal reference for args1 and args2 in first contructor

– max66
Nov 25 '18 at 12:33





I suppose also universal reference for args1 and args2 in first contructor

– max66
Nov 25 '18 at 12:33













What a shame:) Thanks! Compiler errors weren't even close to pointing out, that the problem because of private using. Also, what seems interesting, this code causes clang to infinitely compile and eat all my RAM, although g++ compiles it without problems. And, if I add enable_if, clang will still be saying, that Args1 is empty, as if there was no Id structure.

– Nikita Vorobyev
Nov 25 '18 at 12:37







What a shame:) Thanks! Compiler errors weren't even close to pointing out, that the problem because of private using. Also, what seems interesting, this code causes clang to infinitely compile and eat all my RAM, although g++ compiles it without problems. And, if I add enable_if, clang will still be saying, that Args1 is empty, as if there was no Id structure.

– Nikita Vorobyev
Nov 25 '18 at 12:37















@NikitaVorobyev I removed your contains predicate, and in such a case it may lead to endless recursive calls, because forwarding references generate exact matches.

– Piotr Skotnicki
Nov 25 '18 at 12:38





@NikitaVorobyev I removed your contains predicate, and in such a case it may lead to endless recursive calls, because forwarding references generate exact matches.

– Piotr Skotnicki
Nov 25 '18 at 12:38













@max66 perfect forwarding in this case would require more effort, since Args1 and Args2 cannot be forwarding references (though it is possible to optimize this implementation, like e.g., forwarding the arguments as a tuple and extracting exact amount of elements for each constructor call)

– Piotr Skotnicki
Nov 25 '18 at 12:40







@max66 perfect forwarding in this case would require more effort, since Args1 and Args2 cannot be forwarding references (though it is possible to optimize this implementation, like e.g., forwarding the arguments as a tuple and extracting exact amount of elements for each constructor call)

– Piotr Skotnicki
Nov 25 '18 at 12:40















@PiotrSkotnicki, this was the question, I wanted to ask. How is it possible to perfectly forward Args?

– Nikita Vorobyev
Nov 25 '18 at 12:42





@PiotrSkotnicki, this was the question, I wanted to ask. How is it possible to perfectly forward Args?

– Nikita Vorobyev
Nov 25 '18 at 12:42




















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%2f53467137%2fc-pass-two-parameter-packs-to-constructor%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







這個網誌中的熱門文章

Hercules Kyvelos

Tangent Lines Diagram Along Smooth Curve

Yusuf al-Mu'taman ibn Hud