if constexpr and requires-expression for ad-hoc concepts checking

It works starting from C++2a and gcc 10: https://wandbox.org/permlink/qH34tI6oRJ3Ck7Mm


Here is a working example of using concept inside if constexpr for checking if a type has the method foo with a specific return type T provided as a template parameter:

template<class P, class T>
concept Fooable = requires(P p) {
    requires std::same_as<decltype(p.foo()), T>;
};

template<typename T>
void printIsFooable(const auto& p) {
    if constexpr( Fooable<decltype(p), T> ) {
        std::cout << "fooable <" << typeid(T).name() << ">" << std::endl;
    }
    else {
        std::cout << "not fooable <" << typeid(T).name() << ">" << std::endl;
    }
}

struct MyFoo {
    void foo() const {}
};

int main() {
    printIsFooable<void>(MyFoo{}); // fooable <v>
    printIsFooable<int>(MyFoo{});  // not fooable <i>
    printIsFooable<void>(int{});   // not fooable <v>
}

Code compiles with C++20 in GCC and in Clang.


Concepts issue 3 ("Allow requires-expressions in more contexts") was given WP status in June. And judging by the current looks of [expr.prim.req], in particular p6:

The substitution of template arguments into a requires-expression may result in the formation of invalid types or expressions in its requirements or the violation of the semantic constraints of those requirements. In such cases, the requires-expression evaluates to false; it does not cause the program to be ill-formed.

I'd say your code is fine, and GCC hasn't implemented the resolution of issue 3 properly.