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;
}
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
add a comment |
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
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 ahelper
struct to deduce them
– Piotr Skotnicki
Nov 25 '18 at 12:06
add a comment |
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
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
c++ templates mixins
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 ahelper
struct to deduce them
– Piotr Skotnicki
Nov 25 '18 at 12:06
add a comment |
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 ahelper
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
add a comment |
1 Answer
1
active
oldest
votes
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.
I suppose also universal reference forargs1
andargs2
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 addenable_if
, clang will still be saying, thatArgs1
is empty, as if there was no Id structure.
– Nikita Vorobyev
Nov 25 '18 at 12:37
@NikitaVorobyev I removed yourcontains
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, sinceArgs1
andArgs2
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
|
show 3 more comments
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%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
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.
I suppose also universal reference forargs1
andargs2
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 addenable_if
, clang will still be saying, thatArgs1
is empty, as if there was no Id structure.
– Nikita Vorobyev
Nov 25 '18 at 12:37
@NikitaVorobyev I removed yourcontains
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, sinceArgs1
andArgs2
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
|
show 3 more comments
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.
I suppose also universal reference forargs1
andargs2
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 addenable_if
, clang will still be saying, thatArgs1
is empty, as if there was no Id structure.
– Nikita Vorobyev
Nov 25 '18 at 12:37
@NikitaVorobyev I removed yourcontains
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, sinceArgs1
andArgs2
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
|
show 3 more comments
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.
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.
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 forargs1
andargs2
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 addenable_if
, clang will still be saying, thatArgs1
is empty, as if there was no Id structure.
– Nikita Vorobyev
Nov 25 '18 at 12:37
@NikitaVorobyev I removed yourcontains
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, sinceArgs1
andArgs2
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
|
show 3 more comments
I suppose also universal reference forargs1
andargs2
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 addenable_if
, clang will still be saying, thatArgs1
is empty, as if there was no Id structure.
– Nikita Vorobyev
Nov 25 '18 at 12:37
@NikitaVorobyev I removed yourcontains
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, sinceArgs1
andArgs2
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
|
show 3 more comments
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%2f53467137%2fc-pass-two-parameter-packs-to-constructor%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
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