I have the following class definitions. I would like to create an Alphabet of Letter classes where each Letter class is constructed using an argument from the parameter pack passed to the Alphabet constructor.
#include <tuple>
struct ArgA {};
struct ArgB {};
struct ArgC {};
struct A
{
A(ArgA& param) {}
};
struct B
{
B(ArgB& param) {}
};
struct C
{
C(ArgC& param) {}
};
template <typename ...TLetters>
struct Alphabet
{
template <typename ...TArgs>
Alphabet(TArgs& ...params) : _alphabet(TLetters(params...)...) {}
std::tuple<TLetters...> _alphabet;
};
int main()
{
ArgA argA; ArgB argB; ArgC argC;
Alphabet<A> alphabet1(argA); // Compiles
Alphabet<A, B> alphabet2(argA, argB); // Doesn't compile because argA and argB are passed to A, B and C constructors
Alphabet<A, B, C> alphabet3(argA, argB, argC); // Ditto!
}
The example doesn't compile once I add alphabet2 and alphabet3 as argA, argB and argC are ALL passed to each object's constructor in the TLetters parameter pack (rather than the argument pertaining to it).
Is this possible? Possibly using a std::integer_sequence to recursively iterate over the TArgs parameter pack on the Alphabet constructor? My compiler is only C++11 compliant.
Thanks!
I have the following class definitions. I would like to create an Alphabet of Letter classes where each Letter class is constructed using an argument from the parameter pack passed to the Alphabet constructor.
#include <tuple>
struct ArgA {};
struct ArgB {};
struct ArgC {};
struct A
{
A(ArgA& param) {}
};
struct B
{
B(ArgB& param) {}
};
struct C
{
C(ArgC& param) {}
};
template <typename ...TLetters>
struct Alphabet
{
template <typename ...TArgs>
Alphabet(TArgs& ...params) : _alphabet(TLetters(params...)...) {}
std::tuple<TLetters...> _alphabet;
};
int main()
{
ArgA argA; ArgB argB; ArgC argC;
Alphabet<A> alphabet1(argA); // Compiles
Alphabet<A, B> alphabet2(argA, argB); // Doesn't compile because argA and argB are passed to A, B and C constructors
Alphabet<A, B, C> alphabet3(argA, argB, argC); // Ditto!
}
The example doesn't compile once I add alphabet2 and alphabet3 as argA, argB and argC are ALL passed to each object's constructor in the TLetters parameter pack (rather than the argument pertaining to it).
Is this possible? Possibly using a std::integer_sequence to recursively iterate over the TArgs parameter pack on the Alphabet constructor? My compiler is only C++11 compliant.
Thanks!
Share Improve this question edited Jan 20 at 12:17 463035818_is_not_an_ai 122k11 gold badges99 silver badges208 bronze badges asked Jan 20 at 9:52 pic32cpppic32cpp 715 bronze badges 2 |2 Answers
Reset to default 3You should understand what this TLetters(params...)...
expression does.
You have used ...
twice, so for Alphabet<A, B> alphabet2(argA, argB);
this will expand the expression TLetters(params...)...
to:
A(argA, argB), B(argA, argB)
Which is clearly invalid, since A
or B
do not have matching constructors.
The alternative answer is the simplest fix, but another possible modification of your code is to just drop the extra ...
:
template <typename ...TArgs>
Alphabet(TArgs& ...params) : _alphabet(TLetters(params)...) {}
So in case of Alphabet<A, B> alphabet2(argA, argB);
the problematic expression will expand to the expected: A(argA), B(argB)
https://godbolt.org/z/feo33qhn9
template <typename ...TLetters>
struct Alphabet
{
template <typename ...TArgs>
Alphabet(TArgs& ...params) : _alphabet(params...) {}
std::tuple<TLetters...> _alphabet;
};
It's unnecessary to put TLetters
in the constructor
Demo
Alphabet(TArgs& ...params) : _alphabet(TLetters(params)...) {}
– BoP Commented Jan 20 at 10:00#include <tuple>
, so one can directly copy/paste it and try it. – edrezen Commented Jan 20 at 10:03