Following some of the solutions provided here How can I have multiple parameter packs in a variadic template?, I'm hoping to apply multiple parameter packs to a classes and use CTAD to make the class more usable.
Here is what I came up with (on Coliru), but this gives:
error: class template argument deduction failed
Here is the code I tried:
// A template to hold a parameter pack
template < typename... >
struct Typelist {};
// Declaration of a template
template< typename TypeListOne
, typename TypeListTwo
>
struct Foo;
// A template to hold a parameter pack
template <typename... Args1, typename... Args2>
struct Foo< Typelist < Args1... >
, Typelist < Args2... >
>{
template <typename... Args>
struct Bar1{
Bar1(Args... myArgs) {
_t = std::make_tuple(myArgs...);
}
std::tuple<Args...> _t;
};
template <typename... Args>
struct Bar2{
Bar2(Args... myArgs) {
_t = std::make_tuple(myArgs...);
}
std::tuple<Args...> _t;
};
Bar1<Args1...> _b1;
Bar2<Args2...> _b2;
Foo(Bar1<Args1...>& b1, Bar2<Args2...>& b2) {
_b1 = b1;
_b2 = b2;
}
};
int main()
{
Foo{Foo::Bar1(1, 2.0, 3), Foo::Bar2(100, 23.4, 45)};
return 0;
}
First, CTAD is not done when using the scope resolution operator, so Foo::
can never be used. You must specify the template arguments for this Foo
explicitly.
I suggest you simply move Bar1
and Bar2
outside the Foo
partial specialization into the namespace scope and use
Foo{Bar1(1, 2.0, 3), Bar2(100, 23.4, 45)};
instead.
Then you will get an error that deduction for Foo
fails. This is because only constructors in the primary template are considered for implicit deduction guides. But the constructor that you want to use is in the partial specialization, not the primary template.
So you will need to add an appropriate deduction guide yourself, e.g.:
template <typename... Args1, typename... Args2>
Foo(Bar1<Args1...>, Bar2<Args2...>) -> Foo<Typelist<Args1...>, Typelist<Args2...>>;
Then you will get an error that no constructor is viable. This is because you are taking Bar1<Args1...>& b1
and Bar2<Args2...>& b2
as non-const
lvalue references, but you provide prvalues for them. Non-const
lvalue references cannot bind to rvalues and so you get an error. Either take the parameters by-value or by const
lvalue reference.
Finally you will get an error that _b1
and _b2
do not have default constructors, which is true. They are needed because you are default-initializing _b1
and _b2
in your constructor. You only later assign them values.
So either add default constructors to Bar1
and Bar2
or better use initialization instead of assignment:
Foo(const Bar1<Args1...>& b1, const Bar2<Args2...>& b2) : _b1(b1), _b2(b2) { }
After all these steps the code should compile. I am not sure what exactly your goal is, so not entirely sure whether this will do what you want.