5

The keyword constexpr enforced pretty tight restrictions on functions on its introduction into the C++11 standard. These restrictions were loosened with C++14 and C++20 (most noteworthy):

  • C++14 allowed multiple return statements, static_asserts etc.
  • C++20 allowed try and asm

C++23 further softens these restrictions. From what I can see in cppreference, constexpr for functions seems to only have the following meaning left:

  • it must not be a coroutine
  • for constructor and destructor, the class must have no virtual base classes
  • For constexpr function templates and constexpr member functions of class templates, at least one specialization must satisfy the abovementioned requirements.

C++23 even removed the restriction that a constexpr function must be "evaluatable" at compile time for any type in p2448r2. From my understanding this completely removed the idea of a constexpr function to be evaluated at compile time.

Is that it? If so, how is a constexpr function even useful anymore?

Brotcrunsher
  • 1,964
  • 10
  • 32
  • 7
    It can be evaluated at compile time? – user253751 Jan 23 '23 at 15:39
  • @user253751 So can a none constexpr function, given the "as-if" clause. See also p2448r2: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2448r2.html – Brotcrunsher Jan 23 '23 at 15:40
  • 1
    In practice, if your function is constexpr then the compiler promises it *will* evaluate it at compile time, if at all possible, otherwise it merely makes a feeble attempt. Is this a language-lawyer question? – user253751 Jan 23 '23 at 15:41
  • 2
    Stop thinking that the `constexpr` restrictions designate a set of functions, which has been replaced by a larger set. The changes did not make any user-provided function `constexpr` which was not marked by the programmer. Rather, the `constexpr` keyword defines a set of functions, and the language changes relaxed restrictions on how those functions can be implemented internally. – Ben Voigt Jan 23 '23 at 15:42
  • @user253751 *then the compiler promises it will evaluate it at compile time* is not true. It promises that it can be evaluated at compile time. – NathanOliver Jan 23 '23 at 15:42
  • 1
    @user253751: The compiler promises that it will evaluate it at compile time if it appears in a context where a compile-time constant is required (like initialization of a `constexpr` object) – Ben Voigt Jan 23 '23 at 15:43
  • @NathanOliver that would be an appropriate answer for a language-lawyer question but not for someone who is interested in actual programs and actual compilers. – user253751 Jan 23 '23 at 15:43
  • 1
    @user253751: Actual programs can call `constexpr` functions in ways that will never be evaluated at compile-time, on any current or future compiler. – Ben Voigt Jan 23 '23 at 15:43
  • 5
    I think what you mean to ask: why do we still need to annotate functions as `constexpr`, not "how is a `constexpr` function even useful anymore?" (to which the obvious answer is: it's extremely useful to evaluate code at compile-time?) – Barry Jan 23 '23 at 15:44
  • Basically the same question as https://stackoverflow.com/questions/38879475/why-cant-constexpr-just-be-the-default or https://stackoverflow.com/questions/14472359/why-do-we-need-to-mark-functions-as-constexpr. C++23 doesn't matter really, they could have decided that every function that satisfies the `constexpr` requirements would be automatically `constexpr` already in C++11 (and for lambdas that is actually how it was decided eventually). – user17732522 Jan 23 '23 at 15:44
  • 1
    Please keep in mind that https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2448r2.html explicitly softened the restriction that it needs to be possible to evaluate the function at compile time. – Brotcrunsher Jan 23 '23 at 15:45
  • One nice thing about having to decorate a constant function with `constexpr` is it enforces the constant expression requirements. If you accidently do something non-constant you'll get a nice compiler error instead of the compile silently compiling the code and running it at run time. – NathanOliver Jan 23 '23 at 15:46
  • @NathanOliver No, not since https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2448r2.html was accepted. That's basically my biggest problem, I'll add that to the question itself. – Brotcrunsher Jan 23 '23 at 15:46

1 Answers1

9

What you actually seem to ask is: why not make anything constexpr by default?

Because you might want others to not use a function at compile-time, to give you a possibility to switch to a non-constexpr implementation later.

Imagine this:

  • You see a library function, which you'd like to use at compile-time.

    Let's say, size_t RequiredBufferSize();. If it happens to be constexpr, you can allocate the buffer on the stack, or something like that.

  • You're not sure if it's supposed to work at compile-time, because there's no constexpr in our imaginary language.

  • You try it, and it does work at compile-time. You start using it this way.

    Let's say the implementation was {return 42;}, which is constexpr.

  • A new version of the library is released, the function no longer works at compile-time (e.g. the size is loaded from a config file).

  • You complain to the developer, and he argues that the function was never intended to work at compile-time, and you relied on an implementation detail.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • 1
    I believe this answer is no longer true in C++23 since https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2448r2.html was accepted. – Brotcrunsher Jan 23 '23 at 15:53
  • 3
    @Brotcrunsher Which part specifically? Notice that I'm talking about the opposite scenario (the paper basically suggests to automatically strip `constexpr` if it can't work, while you in your question seem to automatically add it if it can work). – HolyBlackCat Jan 23 '23 at 15:54
  • It is now allowed to call none constexpr functions from constexpr functions, thus making the invocation at compile time impossible in all cases. – Brotcrunsher Jan 23 '23 at 15:56
  • 1
    @Brotcrunsher Mhm, I didn't say otherwise. – HolyBlackCat Jan 23 '23 at 15:57
  • 6
    @Brotcrunsher If the function is marked `constexpr` but actually isn't, there are no lasting consequences. Your code breaks, then the library developer fixes their bug, and it starts working again. But the opposite, if the function isn't marked `constexpr` but actually happens to be, would lock library developers into their implementation details. – HolyBlackCat Jan 23 '23 at 15:59
  • 3
    @Brotcrunsher You could always have a call to a non-`constexpr` function in a `constexpr` function. But if you are actually evaluating the call to the non-`constexpr` function it is not a constant expression. Nothing about this changed. But as explained above, that's not relevant to the answer anyway. – user17732522 Jan 23 '23 at 15:59
  • So does `constexpr` for functions now more or less have a commentary function for other developers rather than applying any actual restrictions while compiling? – Brotcrunsher Jan 23 '23 at 16:07
  • 1
    @Brotcrunsher It's the lack of `constexpr` that applies restrictions to the caller. Previously the presence of `constexpr` also applied restrictions to the implementation, but now only the first part remains. – HolyBlackCat Jan 23 '23 at 16:12
  • For what it's worth, I think this argument is pretty weak. How often have you written a library function that starts out being usable at compile-time and changes to being unusable at compile time? And why is that particular change in contract so important as to merit everyone having to annotate everything? As opposed to adding something like `std::not_usable_in_constant_expressions("nope :-p");` that's just a no-op that's unusuable in constant expressions. – Barry Jan 23 '23 at 16:18
  • Unrelatedly, that macro coroutine library is some serious black magic. Holy black cat is right. – Barry Jan 23 '23 at 16:20
  • @Barry *"How often have you written a library function"* I didn't, but I've seen it happen once: https://github.com/doctest/doctest/issues/473 Mhm, I like your idea more. *"some serious black magic"* Thank you. :P – HolyBlackCat Jan 23 '23 at 16:22
  • @HolyBlackCat Interesting example, but `SIGSTKSZ` wasn't a constexpr function :-) – Barry Jan 23 '23 at 16:48