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!
CodePudding user response:
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.
CodePudding user response:
With C 20, you can create your SumIndices
easily with the Concept library:
#include <concepts>
auto SumIndices(std::same_as<std::size_t> auto ... indices);
However, do note that this have a strict rule on only data of std::size_t
or equivalent types can be passed to the function.
Instead, you might consider to use std::integral
or std::unsigned_integral
, which would allow other integral types to be used:
auto SumIndices(std::integral auto ... indices);