Unrelated deleted operator changes behaviour of overload resolution
c++, c++11, enums, namespaces, overload-resolution
Solution
First off, note that being declared as `delete`d is irrelevant, since deleted functions still take part in overload resolution.
Now, on to overload resolution. Cf. 13.3.1.2/3:
three sets of candidate functions, designated member candidates, nonmember candidates and built-in candidates, are constructed
(There are no member candidates, since `E` is not a class type.) We know from that the operator overload is found by unqualified lookup. So when we consult 3.4.1 ("Unqualified lookup"), we find that
name lookup ends as soon as a declaration is found for the name.
Since you introduce the second operator overload within the namespace `N`, it is found first, and name lookup stops. At this point, the overload set consists of your `int N::operator|(N::F, int)` and the built-in operators. Continuing in 13.3.1.2/6:
The set of candidate functions for overload resolution is the union of the member candidates, the non-member candidates, and the built-in candidates.
Only the builtin is viable (since you cannot convert `E` to `F` implicitly), and thus it is chosen.
Problem
I came across a strange situation today, where declaring a deleted operator with certain arguments changed the behaviour of seemingly unrelated code. I reduced it to the following. Start with this: ``` namespace N { enum E { A, B }; struct C { C(E); private: C(int); }; } N::E operator|(N::E, N::E); namespace N { void Waldo() { C(A | B); } } ``` Notice that C has two constructors, a public one and a private one. This code compiles, indicating that the public overload is being chosen, so the expression `A | B` has type `E`. In turn this means that the `operator|(N::E, N::E)` has been matched (otherwise `A` and `B` would undergo implicit conversion to integers, the type of `A | B` would be `int`, and the private constructor would be matched. So far so good. Now I define a new enumeration type `F`, and a deleted `operator|` that involves F: ``` namespace N { enum E { A, B }; struct C { C(E); private: C(int); }; } N::E operator|(N::E, N::E); namespace N { enum F {}; int operator|(F, int) = delete; void Waldo() { C(A | B); } } ``` Now the code doesn't compile, saying that `C(int)` is private. This indicates that now `A | B` has type `int`, which means `operator|(N::E, N::E)` is no longer being matched. Why did the addition of the deleted `operator|(F, int)` stop `operator|(N::E, N::E)` from being matched?