I tried a version of the prorgam that avoids recursion:
#include <iostream>
template <int N>
constexpr int factorial()
{
int value = 1; // 0! = 1
for (int i = 1; i <= N; i++)
{
value *= i;
}
return value;
}
int main(int argc, const char * argv[])
{
std::cout << factorial<5>() << std::endl;
return 0;
}
It works, and returns 120, as expected.
However, when I try to use recursion, it fails with compile-time errors.
#include <iostream>
template <int N>
constexpr int factorial()
{
if (N == 0) return 1;
return N * factorial<N - 1>();
}
int main(int argc, const char * argv[])
{
std::cout << factorial<5>() << std::endl;
return 0;
}
I'll detail the compile-time errors later...
I tried the recursion version, and expected it to give me 120, as did the non-recursive version.
I'm using XCode on an iMac, with GCC++17. The recursion version gave me the following errors:
Factorial Template
/Users/bryanhiggs/C++ Development/Factorial Template/Factorial Template/main.cpp
/Users/bryanhiggs/C++ Development/Factorial Template/Factorial Template/main.cpp unable to execute command: Illegal instruction: 4
/Users/bryanhiggs/C++ Development/Factorial Template/Factorial Template/main.cpp clang frontend command failed due to signal (use -v to see invocation)
diagnostic msg:
********************
PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
diagnostic msg: /var/folders/zv/nww97t6d3yl_xskx2_k5_jlr0000gn/T/main-5df374.cpp
diagnostic msg: /var/folders/zv/nww97t6d3yl_xskx2_k5_jlr0000gn/T/main-5df374.sh
diagnostic msg: Crash backtrace is located in
diagnostic msg: /Users/bryanhiggs/Library/Logs/DiagnosticReports/clang_<YYYY-MM-DD-HHMMSS>_<hostname>.crash
diagnostic msg: (choose the .crash file that corresponds to your crash)
diagnostic msg:
********************
Is this a bug in GCC++17, or am I misunderstanding something?
Your base-case doesn't work. The compiler stamps out a function for N
= 0 like so:
template <>
constexpr int factorial<0>()
{
if (0 == 0) return 1;
return N * factorial<0-1>();
}
Of course, it does return 1
, but the function still contains the expression factorial<N - 1>()
which must therefore be stamped out.
There are two ways of solving this:
if constexpr
template <int N>
constexpr int factorial()
{
// A compile-time if which drops the non-hitting block immediately
if constexpr (N == 0) return 1;
else return N * factorial<N - 1>();
}
// General function for any N other than 0
template <int N>
constexpr int factorial()
{
return N * factorial<N - 1>();
}
// Specialization for N=0
template<>
constexpr int factorial<0>
{
return 1;
}