Unexpected result of std::is_invocable over a template type

I think it's very important to look at what std::is_invocable does:

Determines whether Fn can be invoked with the arguments ArgTypes.... Formally, determines whether INVOKE(declval<Fn>(), declval<ArgTypes>()...) is well formed when treated as an unevaluated operand, where INVOKE is the operation defined in Callable.

Emphasis mine.

The important part to note here is that std::equal_to<> used inside std::is_invocable will never be evaluated because it's a unevaluated operand. This means that it only checks if operator== exists at all, which it does for std::vector<>, not if it would compile in an evaluated context.


I think, this is correct behavior.

In the first std::is_invokable_v checks for the presence of the operator== in the TNonComparable type. It is not present - so the result is 0.

In the second case std::is_invokable_v checks for the equality operator of the std::vector, which is present and may be invoked. But if do try to invoke it, it won't be able to compile because the TNonComparable type doesn't have operator==. But before you don't try to use it, it won't generate an error.

Maybe, in second case you should check for value_type of the std::vector:

std::cout << std::is_invocable_v<
        std::equal_to<>,
        std::vector<TNonComparable>::value_type,
        std::vector<TNonComparable>::value_type
    > << "\n";
// 0