I’m writing a concept that checks if a type can be used in an expression that composes 2 functions:
template<typename T>
concept C = requires(T t) {
f(g(t));
};
i.e., I want to check if for a given object t of type T, I can call g(t) and then use the resulting value as an argument to f. e.g.,
auto g(int) -> float;
auto g(char) -> double;
void f(float);
void f(double) = delete;
static_assert(C<int>); // g(int) returns a float, so f(float) is called.
static_assert(not C<char>); // g(char) returns a double, but f(double) is deleted
This works just fine.
However, I want to split up the calls to f and g because 1) g may take additional arguments (that don’t depend on T) resulting in a verbose call, and 2) I might want to use the return type/value of g multiple times inside the concept, so I don’t want to repeat the call multiple times.
Naive attempts like the following
auto res = g(t);
f(res);
and
using ret_t = decltype(g(t));
f(ret_t{});
don’t work inside concepts.
Is there some way to achieve the splitting up of f(g(t)) in a way that doesn’t require writing g(t) inside the call to f?
3
1 Answer
A nested requirement can be an option:
template<typename T>
concept C = requires(T t) {
g(t); // Not strictly needed, I think, but explicit verification might be more readable if the concept fails in a template
requires requires(decltype(g(t)) s) { // Can reuse s how many time we want
f(s);
};
};
And yes, requires requires is required here to make sure f(s) is verified as well.
1
-
1
Ah, that's interesting, I hadn't realized requirements could be nested quite like this. (And yes, I would definitely like the explicit verification of
g(t)). I'll try it out, thanks.– cigien11 hours ago



Declare an argument of the return type of
g(t)in the parameter list liketemplate<typename T> concept C = requires(T t, decltype(g(t)) arg) { f(arg); }?11 hours ago
@康桓瑋 Hmm, that could work, although if
g(t)is ill-formed, the concept fails in the parameters to the requires clause rather than in the body of the requires clause. Might not be a terrible option though.11 hours ago
@cigien even if it did fail in the parameters, such substitution failure in a concept simply means that the concept is unsatisfied, not that the program is ill-formed, so it's okay. Using
decltype(g(t))in the parameter list is by far the shortest solution.11 hours ago