On Wed, 16 Nov 2022 at 14:44, Jason McKesson via Std-Discussion <std-discussion@lists.isocpp.org> wrote:
On Wed, Nov 16, 2022 at 5:00 AM Zamfir Yonchev via Std-Discussion
<std-discussion@lists.isocpp.org> wrote:
>
> Hi,
>
> I was wondering why the language doesn't support short-circuiting on logical operations in constexpr context.

It does. The rules of short-circuit evaluation don't change because
something is in a constant expression. Your problem is not a lack of
short-circuit evaluation; your problem is that short-circuit
evaluation doesn't mean what you think it does.

`std::invoke_result_t<F, T>` is ill-formed if `F` is not invokable.
That is not a matter of expression evaluation; that's a matter of
template instantiation. It's not the result of the evaluation that is
ill-formed; it's the *existence* of the expression itself. The literal
text of the source code makes no sense, as far as the language is
concerned. It is no different than if you wrote `a + - + - + c`.

The compiler doesn't get to the point where it would even consider
evaluating the expression because the code doesn't make sense.

`if constexpr` has explicit rules allowing it to discard statements
depending on the result of the constant expression. But that is a
special grammatical construct explicitly designed with this
functionality in mind.

So the reason why what you wrote doesn't work is because there is no
special expression-level construct that was added to the language to
allow discarding of subexpressions in the same way that `if constexpr`
can discard statements.

Ahem. Actually, we do have such a construct in the evaluation of constraints. You can make use of that mode by wrapping your test in `requires requires`:

  constexpr bool test = requires { requires std::is_invocable_v<F, T> && std::is_same_v<std::invoke_result_t<F, T>, int>; };

Demo: https://godbolt.org/z/7q5dvKnsn

https://eel.is/c++draft/expr.prim.req.general#5.sentence-3