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