0
constexpr unsigned long long factorial(unsigned long long n)
{
    return n > 1 ? n * factorial(n - 1) : 1;
}

I have just learnt that if I call a constexpr function using a value known at compile time, the compiler will just replace that function with his final result.

So why do I get a crash at runtime after compiling this call to my function?

std::cout << factorial(10000);

If it was evaluated at compile time, I would get an error just builing my project and it wouldn't even start...

What's wrong?

Simo Pelle
  • 141
  • 1
  • 11
  • Have you attempted to debug? Is `std::cout << factorial(10000);` the exact point at which it crashes? – alteredinstance Jan 28 '20 at 16:46
  • 1
    For one, I think you have an integer overflow. For factorial(50) for me the code works fine, and produces a result which is very close to std::numeric_limits::max() – mutableVoid Jan 28 '20 at 16:46
  • 1
    Do you have optimisations enabled? A quick test with gcc and clang shows they don't evaluate your function unless optimisations are enabled. With optimisations they both just return 0, presumably due to one of the overflowed results equalling `0` making all further results 0 – Alan Birtles Jan 28 '20 at 16:47
  • 3
    TL;DR of the dupes: `constexpr` means can be run at compile time, not must be run. To force it, use it in a constant expression and the the compiler will be forced to use it at compile time. – NathanOliver Jan 28 '20 at 16:48
  • If the `constexpr` isnt being run at compile, we could be seeing a stack overflow causing the crash. A 10000-deep recursion might do that. – alteredinstance Jan 28 '20 at 16:51
  • Yes, I get a stack overflow with MS. But it will work with a debug build if an intermediate is used as [in the example here](https://en.wikipedia.org/wiki/Compile_time_function_execution) – lakeweb Jan 28 '20 at 16:55
  • @alteredinstance yes, I tried to comment all but that command and it crashes anyway – Simo Pelle Jan 28 '20 at 16:59
  • 1
    @mutableVoid I made it on purpose to show the fact that it crashes at runtime – Simo Pelle Jan 28 '20 at 17:02
  • @AlanBirtles how can I enable it? – Simo Pelle Jan 28 '20 at 17:02
  • I'd recommend using a library for your integers (Bigint, Bignum, etc) if you plan on doing factorials of numbers over 500. `10000!` is [36,000 digits long](http://gimbo.org.uk/texts/ten_thousand_factorial.txt). – alteredinstance Jan 28 '20 at 17:02
  • @NathanOliver so should I create a temporary `constexpr` and print that? – Simo Pelle Jan 28 '20 at 17:03
  • @alteredinstance my goal was not to do a factorial of a number over 100... I made it to test if my compiler did really replace my function at compile time – Simo Pelle Jan 28 '20 at 17:04
  • 1
    @Foxel If you want to force it to be evaluated at compile time then yes. C++20 introduces `consteval` which is like `constexpr` but is guaranteed to only be called at compile time that you can use if you don't want to have to force it. – NathanOliver Jan 28 '20 at 17:06
  • @NathanOliver for some reason I can't use it (should I enable some options to use C++20?) – Simo Pelle Jan 28 '20 at 17:08
  • @NathanOliver if I try to create a `constexpr a = factorial(10000)` I get this error: **expression must have a constant value** – Simo Pelle Jan 28 '20 at 17:10
  • What compiler and version are you using? – NathanOliver Jan 28 '20 at 17:10
  • @Foxel Isn't that what you wanted? – NathanOliver Jan 28 '20 at 17:10
  • @NathanOliver yeah, you're right... thank you (I didn't notice that it worked with `constexpr a = factorial(10)` – Simo Pelle Jan 28 '20 at 17:11
  • 1
    My teacher made a mistake while explaining this argument to us ;) – Simo Pelle Jan 28 '20 at 17:13
  • 1
    OK. MSVS doesn't support `consteval` yet. It will probably be in the next version. GCC10 has partial support. – NathanOliver Jan 28 '20 at 17:16
  • @NathanOliver what are MSVS and GCC10? Visual Studio and Code Blocks? – Simo Pelle Jan 29 '20 at 15:59
  • MSVS is [MicroSoft Visual Studio](https://visualstudio.microsoft.com/). GCC is the [GNU Compiler Collection](https://gcc.gnu.org/) – NathanOliver Jan 29 '20 at 16:00

0 Answers0