Overloading istream_iterator -― cannot bind lvalue to ‘std::basic_istream<char>&&’

匿名 (未验证) 提交于 2019-12-03 02:33:02

问题:

I've done some reseach like:

Tell me if I misunderstood some.

I was trying to input std::pair from a file and I wanted to use std::istream_iterator >

Here comes the code:

std::ifstream in("file.in");  std::map<int, int> pp;  pp.insert((std::istream_iterator<std::pair<int, int> >(in)),         std::istream_iterator<std::pair<int, int> >());

I did the overloading as following:

std::istream & operator>>(std::istream & in, std::pair<int, int> & pa) { in >> pa.first >> pa.second; return in; }  std::istream & operator>>(std::istream && in, std::pair<int, int> & pa) { in >> pa.first >> pa.second; return in; }

Here's the Error:

In file included from /usr/include/c++/4.8/iterator:66:0,                  from No_12.cpp:7: /usr/include/c++/4.8/bits/stream_iterator.h: In instantiation of void std::istream_iterator<_Tp, _CharT, _Traits, _Dist>::_M_read() [with _Tp = std::pair<int, int>; _CharT = char; _Traits = std::char_traits<char>; _Dist = long int]’: /usr/include/c++/4.8/bits/stream_iterator.h:70:17:   required from std::istream_iterator<_Tp, _CharT, _Traits, _Dist>::istream_iterator(std::istream_iterator<_Tp, _CharT, _Traits, _Dist>::istream_type&) [with _Tp = std::pair<int, int>; _CharT = char; _Traits = std::char_traits<char>; _Dist = long int; std::istream_iterator<_Tp, _CharT, _Traits, _Dist>::istream_type = std::basic_istream<char>]’ No_12.cpp:23:59:   required from here /usr/include/c++/4.8/bits/stream_iterator.h:121:17: error: cannot bind std::istream_iterator<std::pair<int, int> >::istream_type {aka std::basic_istream<char>}’ lvalue to std::basic_istream<char>&&’       *_M_stream >> _M_value;                  ^    In file included from /usr/include/c++/4.8/iostream:40:0,                  from /files/Nutstore/000/CPPWorkSpace/SHUCourse/DataStructures/BinarySearchTree/20130514/src/BinarySearchTree.hpp:6,                  from /files/Nutstore/000/CPPWorkSpace/SHUCourse/DataStructures/BinarySearchTree/20130514/BinarySearchTree:3,                  from No_12.cpp:1: /usr/include/c++/4.8/istream:872:5: error:   initializing argument 1 of std::basic_istream<_CharT, _Traits>& std::operator>>(std::basic_istream<_CharT, _Traits>&&, _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = std::pair<int, int>]’      operator>>(basic_istream<_CharT, _Traits>&& __is, _Tp& __x)

I don't know what I can do now... Hope that someone can give me some advice. Thanks.

回答1:

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 typedef

According 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:

  • use a wrapper type to wrap std::pair such that you can define the operator>> in a namespace associated with that wrapper type
  • inject your operators in namespace std (not recommended??)


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!