I am trying to get the hang of variadic function/template parameters. However, in the two functions below, I am very confused as to why SumIndices
does not compile (I get the compiler error "expansion pattern ‘std::size_t’ {aka ‘long unsigned int’} contains no parameter packs") while SumValues
does.
template <typename ...t_data_type>
constexpr auto SumValues(t_data_type ..._values) {
return (_values + ...);
}
constexpr auto SumIndices(std::size_t ..._indices) {
return (_indices + ...);
}
I would much appreciate it if anyone can clarify this confusion for me!
In first case you have parameter pack. In second case, you have variadic function from C.
Variadic templates allow you to type-safely pass different types into your function. Example of print with this:
// Create this function to terminate argument depended lookup
void PrintValues(std::ostream&){}
template<typename TFirstArg, typename ...TArgs>
void PrintValues(std::ostream& output, const TFirstArg& arg, const TArgs... other_args){
// Recursive call to another function which has N-1 args
// If other_args are empty, it would call `void PrintValues(std::ostream&)`
// If they are non empty, it would call another instantiation of this template
PrintValues(output << arg, other_args...);
}
And this can be called this way:
PrintValues(std::cout, 5LL, 7.59, "Hello world", std::string{"bingo"});
With varargs you can do this:
void PrintFewNumbers(size_t number_of_args, ...)
{
va_list args;
va_start(args, number_of_args);
for (size_t idx_of_arg, idx_of_arg < number_of_args; ++idx_of_arg){
size_t current_arg = va_arg(args, size_t);
std::cout << current_arg;
}
va_end(args);
}
And you can call it using this:
PrintFewNumbers(0);
PrintFewNumbers(5, 1,2,3,4,5);
You should prefer variadic templates to variadic args because they are type safe. However, they are not always usable.