Hi!
Another thing I found that I'd like in concepts is the notion that e.g. a function related to a type can or shall be evaluated at compile time. For example, this:
```c++
template <typename T>
concept has_foo = requires() {
{ T::foo() /*consteval*/ } -> is_foo_like;
};
```
This is because I may want to use the result of `foo` to distinguish what kind of reflections I should be allowed to use on `T`, and what should be considered a compile error.
Unfortunately, "constexpr-friendliness" is a dynamic property, based on runtime-ish values, not on compile-time-ish types.
Consider:
struct A { static constexpr int foo(int i) { if (i == 42) puts("hi"); return i; } };
template<class T> concept Fantasy = requires (int i) { A::foo(i) consteval; }; // fantasy syntax for "A::foo(i) is constexpr-friendly"
Now, is `Fantasy<A>` true or false?
The expression `A::foo(41)` is certainly constexpr-friendly.
But the expression `A::foo(42)` is not constexpr-friendly; it's evaluable only at runtime.
So what is the constexpr-friendliness of the expression `A::foo(i)` in a vacuum, without knowing the value of `i`? We don't know.
This is a real problem, but I think it's fundamentally unsolvable given the tools we have designed for ourselves in C++.
In fact there's an even harder problem for Concepts, which goes like this:
struct B { static constexpr int bar(int i) { return i; } };
struct C { static consteval int bar(int i) { return i; } };
template<class T> int runtime(int i) { return T::bar(i); } // instantiating with B is OK; with C is ill-formed
template<class T> concept RuntimeFriendly = requires (int i) { T::bar(i); };
static_assert(RuntimeFriendly<B>);
static_assert(not RuntimeFriendly<C>); // we'd like this to succeed, but compilers reject this today
We need a way to distinguish "concepts [or SFINAE] about runtime" from "concepts [or SFINAE] about compile-time." Otherwise, the space of "stuff you can do with a C++ expression" will continue to outpace the space of "stuff you can test with SFINAE/concepts."
I have the vague sense that someone, like Barry, might be working on the latter problem. But maybe that's just because I see people (like Barry) working on fixing up the `consteval` feature and so I blindly assume that this would be part of that whole package.
A solution to the latter problem is certainly required by one or more otherwise-nice papers such as
TLDR, we started with "runtime stuff" and then "compile-time Concepts/SFINAE that lets us ask questions about runtime stuff."
Then we added "constexpr stuff, i.e. a compile-time runtime"; but we failed to add "compile-time compile-time stuff that lets us ask questions about the compile-time stuff."
Off the top of my head, I suppose one possible syntax for this would be, like,
template<class T> concept constexpr Fantasy = requires (int i = 42) { A::foo(i); };
template<class T> concept RuntimeFriendly = requires (int i) T::bar(i); };
template<class T> concept consteval DontCareAboutRuntime = requires (int i = 42) { A::allocate(i); };
where `DontCareAboutRuntime<std::allocator<int>>` might be `true` on freestanding, even though no runtime function `A::allocate` would exist.
Notice the explicit providing of "default values" for each requires-expression parameter.
HTH,
Arthur