Hmm, is that just because of the template resolution? (and so wouldn't apply to constexpr in C)
AFAICT, something about the template declarations is making the call of f(x) to be "who could know" (which should just be fail).
The same thing with concrete types says that f isn't constexpr [3]. And you have to make it actually constexpr by removing the static from counter [4].
[1] https://docs.microsoft.com/en-us/cpp/cpp/constexpr-cpp?view=...
[2] https://godbolt.org/z/7rGWbP1xz
That's not really true. You don't get that "certainty" with constexpr either:
Notice you won't even get a warning with -Weverything under Clang!> Edit: is the argument that const static is also that? (If so, only for direct initialization of structures / you still can't have the equivalent of a constexpr function).
For variables, const static should probably evaluate at compile time whenever possible, like you mentioned.
For functions, constexpr is really useless (again, see above as just one example) and an inline declaration serves pretty much the same practical purpose. I think you're thinking of 'consteval', which is at least not completely useless, so it's a little easier to justify. Even then, it should've probably been an attribute rather than a keyword.