constexpr isn't just a claim about today - it's a promise for the future. That is, the compiler can certainly notice that a function can be evaluated at compile time, and indeed optimizers will often perform enough inlining and constant propagation to boil down function calls to constant values in the binary. The constexpr keyword serves two purposes: it claims that the implementation is usable in constant expressions today (therefore allowing compilers to diagnose (i.e. emit compiler errors for) things that can't be done at compiletime, like I/O), and it promises that the implementation won't change in the future to be hostile to compile-time evaluation. This promise is important - otherwise, users could take a dependency on a function's current behavior (e.g. by using its result as an array bound, or as a template argument), and then they would be broken by implementation changes in the future that prohibited compile-time evaluation.