I want to ask if the following code is valid.
I wonder about the possibility to expand parameter packs multiple times in one expression.
#include <iostream>
#include <tuple>
class ExpandWithConstructor
{
public:
template <typename ... T>
ExpandWithConstructor( T... args) { }
};
template <typename T>
int PrintArgs( T arg )
{
std::cout << arg << ", ";
return 0;
}
template <typename Head, typename ... T>
class DebugPrinter: public DebugPrinter<T...>
{
public:
DebugPrinter() { }
template< typename ...Y>
DebugPrinter( Y ... rest )
{
std::cout << "Construction of: " << __PRETTY_FUNCTION__ << " Values: " ;
ExpandWithConstructor{PrintArgs( rest)...};
std::cout << std::endl;
}
};
template <typename Head>
class DebugPrinter< Head >
{
public:
};
template <typename ... T>
class TypeContainer: public std::tuple<T...>
{
public:
TypeContainer(T... args):std::tuple<T...>(args...){};
};
template <typename... T1> class CheckVariadic;
template <typename... T1, typename ...T2>
class CheckVariadic< TypeContainer<T1...>, TypeContainer<T2...>> :
public DebugPrinter< T1, T2, T1...>...
{
public:
CheckVariadic( T1... args1, T2... args2, T1... args3): DebugPrinter< T1, T2, T1...>(args1, args2..., args1)... {}
};
int main()
{
CheckVariadic< TypeContainer<int,float>, TypeContainer<char, void*>> checkVariadic1{ 1,2.2,'c',(void*)0xddddd,5,6.6,};
}
As you can see the code uses : DebugPrinter< T1, T2, T1...>...
if T1 is given with "int,float" and T2 is "char,void*" which expands to
DebugPrinter< T1, T2, int, float>...
which expands to
DebugPrinter< int, char, int, float>
DebugPrinter< float, void*, int, float>
The same expansion goes with:
DebugPrinter< T1, T2, T1...>(args1, args2..., args1)...
The code compiles with clang3.3 but NOT with gcc4.8.1 so I want to ask if the code is valid or not.
Update: gcc 7.2 still did not compile the code.
Yes your code is perfectly valid. A pack expansion consists of a pattern and an ellipsis and can appear in a pattern of another pack expansion. In paragraph §14.5.3/5 of the standard you will find:
[...] An appearance of the name of a parameter pack is only expanded by the innermost enclosing pack expansion. The pattern of a pack expansion shall name one or more parameter packs that are not expanded by a nested pack expansion; [...]
A pack expansion can be used in any context mentioned in §14.5.3/4. Given your example:
DebugPrinter< T1, T2, T1...>...
Both pack expansions are valid. The context of the first one is a template-argument-list
while the second appears in a base-specifier-list
.
The example provided by the standard text:
template<class ... Args>
void g(Args ... args) { // OK: Args is expanded by the function
// parameter pack args
f(const_cast<const Args*>(&args)...); // OK: “Args” and “args” are expanded
f(5 ...); // error: pattern does not contain any
// parameter packs
f(args); // error: parameter pack “args” is not
// expanded
f(h(args ...) + args ...); // OK: first “args” expanded within h,
// second “args” expanded within f
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With