I'm exploring constant expressions in combination with templates in C++, and I've run into a problem I cannot understand.
I want to check if the value of a template argument (in my case an unsigned int) is zero, but the compiler never thinks the value is zero even though I have a static_assert that confirms that it has actually passed below zero.
I'm implementing a simple (or at least I thought so) template function that is supposed to just summarize all integer values in the range from e.g. 5 down to zero.
It's supposed to perform a recursive invocation of the template function until it reaches zero, and then it should stop, but the compiler never thinks the template parameter value is zero.
Here's my problematic function:
template <unsigned int Value>
constexpr unsigned int sumAllValues()
{
static_assert (Value >= 0, "Value is less than zero!");
return Value == 0 ? 0 : Value + sumAllValues<Value - 1>();
}
And it's invoked like this:
constexpr unsigned int sumVals = sumAllValues<5>();
For some reason the compiler never thinks Value == 0, and hence it continues until it stops on the static_assert. If I remove the assert the compiler continues until it reaches the max instantiation depth:
error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) return Value == 0 ? 0 : Value + sumAllValues();
What am I doing wrong in the above function? Can I not check the value of the template parameter itself?
I was inspired by an example I found on Wikipedia:
template<int B, int N>
struct Pow
{
// recursive call and recombination.
enum{ value = B*Pow<B, N-1>::value };
};
template< int B >
struct Pow<B, 0>
{
// ''N == 0'' condition of termination.
enum{ value = 1 };
};
int quartic_of_three = Pow<3, 4>::value;
See reference: C++11
And I actually do have a working example which is constructed more in the way the above Pow example code is:
template <unsigned int Value>
constexpr unsigned int sumAllValues()
{
static_assert (Value > 0, "Value too small!");
return Value + sumAllValues<Value - 1>();
}
template <>
constexpr unsigned int sumAllValues<0>()
{
return 0;
}
And it's invoked in the same way as my problematic function:
constexpr unsigned int sumVals = sumAllValues<5>();
It also performs a recursive invocation of the template function until it reaches zero. The zero case has been specialized to interrupt the recursion. This code works, and produces the value 15 if I input 5 as template argument.
But I thought I could simplify it with the function I'm having problems with.
I'm developing on Linux (Ubuntu 18.04) in Qt 5.12.2.
Update:
StoryTeller suggests a working solution which is to use the C++17 feature "if constexpr" to halt the recursion:
template <unsigned int Value>
constexpr unsigned int sumAllValues()
{
if constexpr (Value > 0)
return Value + sumAllValues<Value - 1>()
return 0;
}