https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113117
Bug ID: 113117 Summary: ambiguous call during operator overloading is not detected for templates Product: gcc Version: 13.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: armagvvg at gmail dot com Target Milestone: --- In a nutshell: the next code snippet is compiled successfully, but shouldn't be according to a language standard: struct S { template <class T> S& operator<<(T) { return *this; } }; template <class T> T& operator<<(T& s, int) { return s; } int main () { S s; s << 1; } Details: Operator overloading for classes can be implemented with free functions and with class member. When both exist, the C++ standard (I used C++17, part 16.5.2 - Overloaded Operators -> Binary operators) says that "If both forms of the operator function have been declared, the rules in 16.3.1.2 determine which, if any, interpretation is used.". The set of candidates contains both the member and the free function then. The member is considered as a free function with first implicit parameter (16.3.1 - Candidate functions and argument lists) - "a member function is considered to have an extra parameter, called the implicit object parameter, which represents the object for which the member function has been called". Thus we have two templates here: 1. template <class T> T& operator<<(T&, int) - defined in the code 2. template <class T> S& operator<<(S, T) - synthesized from the member function 16.3.3 "Best viable function" mentions that "F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 17.5.6.2...". But no one template is more specialized for a call "operator<<(S, int)". Thus we have two best viable functions and "If there is exactly one viable function that is a better function than all other viable functions, then it is the one selected by overload resolution; otherwise the call is ill-formed". This code snippet should be ill-formed. But it doesn't. clang detects this as an error.