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.