Reputation: 117
Suppose I want to define a C++ function that has no Input Parameters within bracket, but within the <>
argument. I have a Parameter pack as Input Arguments. Meaning that I have to write, for example, a function
int calculate<args...>()
{
return 1 + calculate<some_arg,args...>();
}
And also a base case implementation I have to give. However, I am confronted with a lot of Compiler Errors, because I don't know how to write such a form of recursion out properly. What I have to write before the above function declaration?
template<int... args>
(if data type of args is int; any other data type is also possible in a similar way)? Or what I have to write to avoid Compiler Errors? I also tried
template<int some_arg,int... args>
But I don't know also how to deal with variadic templates (how to unpack them). Any help?
EDIT:
My attempt for one Special case
template<bool... dg>
int calculate<0>()
{
return 1;
}
Error message for this is:
error: expected initializer before ‘<’ token
Upvotes: 1
Views: 916
Reputation: 3
Another way to do recursion allows you to do it in a single function, utilizing the sizeof...
operator:
template<int lhs, int... rhs>
int add()
{
if constexpr(sizeof...(rhs))
{
return lhs + add<rhs...>();
}
else
{
return lhs;
}
}
This also requires C++17 for if constexpr
, but it can do things that fold expressions might not be able to.
Upvotes: 0
Reputation: 26
If you're using C++17+: refer to dfrib's answer
Here's how you would implement a function to add the elements of a parameter pack using template recursion
template<int arg>
constexpr int add()
{
return arg;
}
template<int arg1, int arg2, int... args>
constexpr int add()
{
return arg1 + add<arg2, args...>();
}
Regarding if you wanted to create a special case
template<int arg>
constexpr int calculate()
{
return arg;
}
template<> int calculate<0>() { return 1; } // special case
template<int arg1, int arg2, int... args>
constexpr int calculate()
{
return calculate<arg1>() + calculate<arg2,args...>();
}
This would make it to where every time you have a zero in you argument list, it will add 1 instead of 0
Upvotes: 1
Reputation: 73176
But I don't know also how to deal with variadic templates (how to unpack them). Any help?
As of C++17 you needn't resort to recursion, but can use pack expansion:
#include <iostream>
template<int ...Args>
constexpr int calculate() {
return (Args + ...);
}
int main() {
std::cout << calculate<1, 2, 3>(); // 6
}
If you want to allow other types of non-type template parameters, you can make use of a placeholder type (auto
) for non-type template parameters, also a C++17 feature:
template<auto ...Args>
constexpr auto calculate() {
return (Args + ...);
}
As you cannot partially specialize function templates, you will have to use delegation to a class template if you want to provide different implementations for different specializations:
#include <iostream>
#include <ios>
template<auto ...Args>
struct calculate_impl {
static constexpr auto calc() { return (Args + ...); }
};
template<bool ...Args>
struct calculate_impl<Args...> {
static constexpr bool calc() { return (Args && ...); }
};
template<auto ...Args>
constexpr auto calculate() {
return calculate_impl<Args...>::calc();
}
int main() {
std::cout << calculate<1, 2, 3>(); // 6
std::cout << std::boolalpha
<< "\n" << calculate<false,true>() // false
<< "\n" << calculate<true, true>(); // true
}
Upvotes: 4