concept to check existence of function in class (problem in GCC?)

First, the way to check a concept is just to static_assert (not to try to instantiate a constrained class template).

static_assert(HasCallOperator<functor>);
static_assert(HasCallOperator<functorOverloaded>);
static_assert(HasCallOperator<functorTemplated>);

Second, you can't write t.operator() for the same reason that you can't write f.fun for any other non-static member function: if you do class member access, it must end with invocation. So this is simply a clang/msvc bug that it allows any of this.

And then &C::operator() will not work if the call operator is overloaded or a function template (or both).

Which really calls into question the whole point of this, since without reflection we're highly limited in the kinds of answers we can give to these questions. You can really only address the simple case of non-overloaded, non-template call operator.


Nevertheless, there is an approach that works here. The trick is the same problem we have in our present case: &C::operator() doesn't work if operator() is overloaded.

So what we do instead is construct a case where &C::operator() would be overloaded if there were one, and invert the check. That is:

#include <type_traits>

struct Fake { void operator()(); };
template <typename T> struct Tester : T, Fake { };

template <typename C>
concept HasCallOperator = std::is_class_v<C> and not requires(Tester<C> t)
{
    &Tester<C>::operator();
};

HasCallOperator<C> doesn't check C, it checks a type that inherits from both C and a type that has a non-overloaded non-template call operator. If &Tester<C>::operator() is a valid expression, that means it refer to &Fake::operator(), which means that C did not have one. If C had a call operator (whether it's overloaded or a template or both or neither), then &Tester<C>::operator() would be ambiguous.

The is_class_v check is there to ensure that stuff like HasCallOperator<int> is false rather than ill-formed.

Note that this won't work on final classes.