Reputation: 4022
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?
Upvotes: 16
Views: 2274
Reputation: 137425
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.
Upvotes: 22
Reputation: 17708
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)
Upvotes: 9