Template factorial function without template specialization
The problem is that f<N>()
always instantiates f<N-1>()
whether that if branch is taken or not. Unless properly terminated, that would create infinite recursion at compile time (i.e. it would attempt instantiating F<0>
, then f<-1>
, then f<-2>
and so on). Obviously you should terminate that recursion somehow.
Apart from constexpr
solution and specialization suggested by NathanOliver, you may terminate the recursion explicitly:
template <int N>
inline int f()
{
if (N <= 1)
return 1;
return N * f<(N <= 1) ? N : N - 1>();
}
Mind, this solution is rather poor (the same terminal condition must be repeated twice), I'm writing this answer merely to show that there are always more ways to solve the problem :- )
The issue here is that your if statement is a run time construct. When you have
int f() {
if (N == 1) return 1; // we exit the recursion at 1 instead of 0
return N*f<N-1>();
}
the f<N-1>
is instantiated as it may be called. Even though the if condition will stop it from calling f<0>
, the compiler still has to instantiate it since it is part of the function. That means it instantiates f<4>
, which instantiates f<3>
, which instantiates f<2>
, and on and on it will go forever.
The Pre C++17 way to stop this is to use a specialization for 0
which breaks that chain. Starting in C++17 with constexpr if, this is no longer needed. Using
int f() {
if constexpr (N == 1) return 1; // we exit the recursion at 1 instead of 0
else return N*f<N-1>();
}
guarantees that return N*f<N-1>();
won't even exist in the 1
case, so you don't keep going down the instantiation rabbit hole.