I would like to modify an existing class constructor:
template< typename T, typename... Ts >
MyClass( std::vector<T>& head, Ts& ...tail );
So that a processing flag can be specified:
template< typename T, typename... Ts >
MyClass( MyEnum myEnum, std::vector<T>& head, Ts& ...tail );
This works fine, however I was wondering if there is a way for it to be specified as the right-most argument, and possibly with a default value. I've never seen variadic templates declared like that, but then again, I can't find anything explicitly stating that they can't be. I tried:
template< typename T, typename... Ts >
MyClass( std::vector<T>& head, Ts& ...tail, MyEnum myEnum );
...
MyClass myClass( dataA, dataB, dataC, MyEnum::VALUE );
But the compiler does not like it, I'm assuming it is due to how variadic templates are resolved and that they must be the right-most parameter?
Is this possible in C++11?
Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.
You don't have to do anything special to call a variadic function. Just put the arguments (required arguments, followed by optional ones) inside parentheses, separated by commas, as usual. But you must declare the function with a prototype and know how the argument values are converted.
It's not illegal to have a function parameter pack in the middle, but you run into a gigantic hurdle when you try to do this with a constructor: a function parameter pack that does not occur at the end of the parameter-declaration-list is a non-deduced context (§14.8.2.5 [temp.deduct.type]/p5, last bullet point), and constructor templates must be called using template argument deduction - you can't explicit specify their template parameters.
That is, to have a function parameter pack in the middle, you must explicitly specify the template parameters when you call the function:
template< typename T, typename... Ts >
void test( const std::vector<T>& head, const Ts& ...tail, MyEnum myEnum ) { }
test<double, int>(std::vector<double>(), 10, MyEnum()); // legal
But this will not compile:
test(std::vector<double>(), 10, MyEnum()); // No deduction performed for the parameter pack
There is, however, no way in the language to explicitly specify the template parameters of a constructor template when you call it (§14.8.1 [temp.arg.explicit]/p7):
[ Note: Because the explicit template argument list follows the function template name, and because conversion member function templates and constructor member function templates are called without using a function name, there is no way to provide an explicit template argument list for these function templates. —end note ]
Thus, for constructors, you have to rely on template argument deduction - which doesn't work if your function parameter pack is not at the end.
You can "wrap" the variadic in an std::tuple
:
template< typename T, typename... Ts >
MyClass( std::vector<T>& head, std::tuple<Ts& ...> tail, MyEnum myEnum );
...
MyClass myClass( dataA, std::tie( dataB, dataC ), MyEnum::VALUE );
// NOTE: ^^^^^^^^^ ^
Live example (rev 2)
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