The short version is
#include <functional>
consteval bool f() { return false; }
static_assert( std::not_fn(f)() ); // this is ok
static_assert( std::not_fn<f>()() ); // but this is ill-formed
auto x = std::not_fn<f>(); // ... because this is ill-formed
f is an immediate function. There are tight restrictions around how it can be used. Basically, it can be used in an immediate function context or as part of an expression that is a constant expression.
In particular, there are some things you cannot do with immediate functions. The result of a constant expression cannot include a pointer (or reference) to immediate function anywhere all the way down. Which means that std::not_fn<f>() is ill-formed because initializing the constant template parameter of std::not_fn with f would be a constant expression that has a "constituent value" that is an immediate function. That's just not allowed. And it's important to understand why this might be the case:
consteval bool is_even(int x) { return x % 2 == 0; }
template <auto F>
bool call_f(int x) { return F(x); }
int main(int argc, char**) {
return call_f<is_even>(argc);
}
If we were allowed to initialize the constant template argument with is_even, then what would prevent the call F(x)? F would just be a bool(*)(int) at that point right? But that would require persisting the function to runtime, which consteval is expressly there to avoid doing.
But this is fine:
static_assert( std::not_fn(f)() );
The use of f there makes this immediate-escalating which requires the whole expression to either be constant (which it is) or within an immediate function context (which it also is), so that works.
Note that Peter Dimov and I have a paper (P3603) which seeks to address this issue by properly formalizing the notion of consteval-only value, which would permit std::not_fn<f> to work by effectively being able to propagate through the "consteval-ness" of the value. Or, for my is_even example earlier, call_f<is_even> itself would be fine, but the call F(x) in the body would be ill-formed because it would have to be constant (and it is not).