The following code can not compile in my visual studio 2019. But if I delete the first overloading of >> it would compile.
The code can compile by g++ which confused me. I guess it is about different locations where the template function is generated by the compiler?
Error message: error C2679: binary '>>': no operator found which takes a right-hand operand of type 'std::vector<int,std::allocator<_T>>'
#include <iostream>
#include <vector>
typedef std::vector<int> Mon; // ordered
typedef std::vector<Mon> Poly; // ordered
class A {};
// It would compile successfuly if this function is removed
std::istream& operator>>(std::istream& sin, A& a)
{
return sin;
}
template <typename Container>
void load(std::istream& sin, Container& cont)
{
typename Container::value_type n;
sin >> n;
}
std::istream& operator>>(std::istream& sin, Mon& mon)
{
load(sin, mon);
return sin;
}
std::istream& operator>>(std::istream& sin, Poly& poly)
{
load(sin, poly);
return sin;
}
int main()
{
return 0;
}
The underlying problem is that this function signature in global namespace:
std::istream& operator>>(std::istream& sin, std::vector<int>& mon);
cannot be found by argument-dependent lookup. Since all of the arguments are in std
, the ADL only searches std
and not the global namespace.
To avoid this sort of problem you can follow a rule of thumb: don't overload operators in such a way that they will not be found by ADL. (Corollary: you shouldn't try to make vector<Foo> v; cin >> v;
work).
Firstly, note that the syntax sin >> n
translates to performing both operator>>(sin, n)
and sin.operator>>(n)
and combining all results, as described in full here.
The code in the question is quite similar to this question and I will summarize the findings of the top answer there.
For this function:
template <typename Container>
void load(std::istream& sin, Container& cont)
{
typename Container::value_type n;
sin >> n;
}
specifically when the lookup of operator>>(sin, n)
happens, the operator>>
is a dependent name because it's the name of a function call whose argument types depend on the template parameter.
When name lookup is applied to a dependent function name (ref: [temp.dep.candidate]) the rules are:
extern
functions defined elsewhere in the program that would have been found by ADL if they had a visible declaration at the point of instantiation, and these extra declarations would have affected the overload resolution, then the program has undefined behaviour (no diagnostic required).(NOTE: My first version of this answer incorrectly quoted Rule 3 and so drew the wrong conclusion):
So the lookup of sin >> n
instantiated from the call load(sin, mon);
succeeds because the member function std::istream::operator>>(int&)
is found. (The search also found the A&
version but overload resolution selects the member function).
The problem arises with the lookup of sin >> n
instantiated by load(sin, poly);
.
According to Rule 1, operator>>(std::istream&, A&)
is found. (This function would later be discarded by overload resolution, but at this stage we are just performing name lookup).
According to Rule 2, the ADL namespace list is: std
. So this step will find std::operator>>
(various overloads), but not ::operator>>(istream&, Mon&);
since that is not in namespace std
.
Rule 3 doesn't apply since there aren't any overloads in namespace std
that would accept a Mon
.
So the correct behaviour is:
sin >> n
when instantiating load(sin, poly);
.It would compile successfully if this function is removed
there should actually be no difference; the code should still fail compilation for the same reason.CONCLUSION: It appears to me that:
I note that if we change operator>>
to bar
and sin >> n
to bar(sin, n);
then gcc and msvc correctly reject both versions. gcc even gives a very similar error message to clang.
So I conjecture that the bug might be an incorrect application of the overloaded operator name lookup rules -- which differ slightly to non-operator names but not in any way pertaining to this code example.
For an in-depth writeup of the rationale for these rules and the behaviour of MSVC, see this excellent article.