I\'ve done some reseach like:
To understand what's the problem, we have to take a look at an exemplary implementation of istream_iterator
(the problem arises from the requirements of the Standard, which are implicitly shown here):
template < class T, class CharT, class Traits, class Distance >
class istream_iterator
{
/* ... */
typedef std::basic_istream<CharT, Traits> istream_type;
istream_type* stored_istream_ptr;
T value;
public:
/* ... */
istream_iterator& operator++()
{
*stored_istream_ptr >> value; // (A)
return *this;
}
T const& operator*() const
{
return value;
}
/* ... */
};
In line (A), an operator is applied to objects of dependent types:
value
is of type T
stored_istream_ptr
is of type istream_type
, see the typedefAccording to [temp.dep.type]/8, both types are dependent.
For the expression A >> B
as well as for any other function call, first the name of the function is looked up (here: operator>>
) -> name lookup, then, from the set of found functions (overloads), the most viable is chosen and called -> overload resolution.
For an operator, both member and non-member functions (such as your operators) are looked up.
In this case, the involved types are dependent, therefore special rules for name lookup apply [temp.dep.res]/1:
In resolving dependent names, names from the following sources are considered:
- Declarations that are visible at the point of definition of the template.
- Declarations from namespaces associated with the types of the function arguments both from the instantiation context (14.6.4.1) and from the definition context.
Your operators have been defined in the global namespace, which is not associated to neither std::basic_istream
nor std::pair
. Therefore, name resolution does not find your operators and overload resolution for the expression in line (A) fails.
This would explain clang 3.2's error message:
stream_iterator.h:120:17: error: invalid operands to binary expression ('istream_type' (aka 'basic_istream < char, std::char_traits >') and 'std::pair')
*_M_stream >> _M_value; ~~~~~~~~~~ ^ ~~~~~~~~
And it explains why the workarounds work.
g++ on the other hand seems to only show one overload found by name resolution and the reason it's rejecting it (whereas clang++ shows all overloads found by name resolution with a reason for every single one why it has been rejected). The one g++ shows might be the "best fitting":
template< class CharT, class Traits, class T >
basic_istream<CharT,Traits>& operator>>(basic_istream<CharT,Traits>&&, T&);
Which is, AFAIK, just a wrapper to call the other operator>>
in the case the expression istream_obj >> value
operates on a rvalue (like get_istream() >> value
).
This is unrelated to your problem (and confusing).
Two workarounds:
std::pair
such that you can define the operator>>
in a namespace associated with that wrapper type