Search code examples
c++templatesc++-conceptsrequires-expression

How to reuse the return type of a function call inside a requires expression?


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?


Solution

  • 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.