【问题标题】:Overloading istream_iterator ---- cannot bind lvalue to ‘std::basic_istream<char>&&’重载 istream_iterator ---- 无法将左值绑定到‘std::basic_istream<char>&&’
【发布时间】:2013-05-14 13:47:09
【问题描述】:

我做了一些研究,例如:

如果我误解了一些,请告诉我。

我试图从文件中输入 std::pair 并且我想使用 std::istream_iterator >

代码来了:

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> >());

我做了如下重载:

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; }

这是错误:

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)

我不知道我现在能做什么...... 希望有人能给我一些建议。 谢谢。

【问题讨论】:

  • 另外,我用的是g++-4.8
  • 在我看来,您的运营商找不到(名称解析)。我会尝试获取更多信息并发布答案。
  • 为什么第二次重载?在我看来这是你的问题。通常的习惯用法是只提供第一个重载。
  • @JamesKanze 不能解决问题;事实上,将它们放在 clang 3.2 中的命名空间 std 中确实可以解决问题 - 虽然我不知道为什么。
  • 如果涉及到从属名称就有意义了,我仍在试图弄清楚在哪里。

标签: c++


【解决方案1】:

要了解问题所在,我们必须看一下istream_iterator 的示例实现(问题源于标准的要求,此处隐含显示):

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;
    }
    /* ... */
};

在 (A) 行中,运算符应用于依赖类型的对象:

  • valueT 类型
  • stored_istream_ptristream_type 类型,见 typedef

根据[temp.dep.type]/8,两种类型都是依赖的。

对于表达式A &gt;&gt; B 以及任何其他函数调用,首先查找函数的名称(此处为:operator&gt;&gt;)-> 名称查找,然后从一组找到的函数(重载),选择并调用最可行的 -> 重载分辨率

对于运算符,会同时查找成员函数和非成员函数(例如您的运算符)。

在这种情况下,所涉及的类型是依赖的,因此 name 查找的特殊规则适用 [temp.dep.res]/1:

在解析从属名称时,会考虑来自以下来源的名称:

  • 在模板定义处可见的声明。
  • 来自与函数参数类型相关的命名空间的声明,来自实例化上下文 (14.6.4.1) 和定义上下文。

您的运算符已在全局命名空间中定义,该命名空间与std::basic_istreamstd::pair 均无关。因此,name 解析找不到您的运算符,并且 (A) 行中的表达式的 overload 解析失败。


这可以解释 clang 3.2 的错误信息:

stream_iterator.h:120:17:错误:二进制表达式('istream_type'(又名'basic_istream ')和'std::pair')的操作数无效

       *_M_stream >> _M_value;
       ~~~~~~~~~~ ^  ~~~~~~~~

它解释了为什么这些变通方法有效。

另一方面,

g++ 似乎只显示了通过名称解析找到的一个重载及其拒绝它的原因(而 clang++ 显示了通过名称解析找到的 all 重载,并说明了每个重载的原因已被拒绝)。一个 g++ 节目可能是“最合适的”:

template< class CharT, class Traits, class T >
basic_istream<CharT,Traits>& operator>>(basic_istream<CharT,Traits>&&, T&);

这是,AFAIK,只是一个包装器来调用另一个 operator&gt;&gt; 在表达式 istream_obj &gt;&gt; value 对右值进行操作的情况下(如 get_istream() &gt;&gt; value)。

这与您的问题无关(并且令人困惑)。


两种解决方法:

  • 使用包装器类型来包装std::pair,以便您可以在与该包装器类型关联的命名空间中定义operator&gt;&gt;
  • 在命名空间 std 中注入您的运算符(不推荐??)

【讨论】:

  • 关于包装类:这可能是从std::pair&lt;int, int&gt; 派生的合理案例。否则,operator std::pair&lt;int, int&gt;() const 可以解决问题。 (我经常这样做,我迭代的类型实际上类似于struct { char const* key, int value; operator std::pair&lt;std::string, int&gt;() const; };,可以静态初始化。)
  • 哇...这太棒了!!!但是......一个小问题......如果我使用包装类,我将不得不更改我的代码中的所有其他内容来完成这个......
  • @Adam 我找到了解决方法,请参阅this question的第二部分
猜你喜欢
  • 2014-05-24
  • 2022-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-27
  • 2018-03-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多