Перегрузка istream_iterator ---- не может привязать lvalue к 'std:: basic_istream<char>&&'
Я сделал некоторые исследования, как:
- Оператор перегрузки<<: не может связать lvalue с 'std::basic_ostream&&'
- Оператор перегрузки<<: не может связать значение 'std:: basic_ostream' со значением 'std::basic_ostream&&'
- ошибка: невозможно связать значение 'std:: basic_ostream' со значением 'std::basic_ostream&&'
Скажи мне, если я неправильно понял.
Я пытался ввести 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)
Я не знаю, что я могу сделать сейчас... Надеюсь, что кто-то может дать мне совет. Благодарю.
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) оператор применяется к объектам зависимых типов:
value
имеет типT
stored_istream_ptr
имеет типistream_type
см. typedef
Согласно [temp.dep.type]/8, оба типа являются зависимыми.
Для выражения A >> B
как и для любого другого вызова функции, сначала ищется имя функции (здесь: operator>>
) -> поиск имени, тогда из набора найденных функций (перегрузок) выбирается и называется наиболее жизнеспособным -> разрешение перегрузки.
Для оператора ищутся как функции-члены, так и функции, не являющиеся членами (например, ваши операторы).
В этом случае задействованные типы являются зависимыми, поэтому применяются специальные правила для поиска имени [temp.dep.res]/1:
При разрешении зависимых имен учитываются имена из следующих источников:
- Объявления, которые видны в точке определения шаблона.
- Объявления из пространств имен, связанные с типами аргументов функции, как из контекста экземпляра (14.6.4.1), так и из контекста определения.
Ваши операторы были определены в глобальном пространстве имен, которое не связано ни с std::basic_istream
ни std::pair
, Следовательно, разрешение имен не находит ваших операторов, и разрешение перегрузки для выражения в строке (A) не выполняется.
Это объяснило бы сообщение об ошибке clang 3.2:
stream_iterator.h: 120: 17: ошибка: недопустимые операнды в двоичном выражении ('istream_type' (он же 'basic_istream
') и 'std::pair') *_M_stream >> _M_value; ~~~~~~~~~~ ^ ~~~~~~~~
И это объясняет, почему обходные пути работают.
С другой стороны, g++, похоже, показывает только одну перегрузку, обнаруженную разрешением имени, и причину, по которой он отклоняет ее (тогда как clang++ показывает все перегрузки, обнаруженные разрешением имени, с указанием причины, по которой она была отклонена). Одно из представлений g++ может быть "лучшим соответствием":
template< class CharT, class Traits, class T >
basic_istream<CharT,Traits>& operator>>(basic_istream<CharT,Traits>&&, T&);
Который, AFAIK, просто обертка для вызова другого operator>>
в случае выражения istream_obj >> value
работает на значение (как get_istream() >> value
).
Это не связано с вашей проблемой (и сбивает с толку).
Два обходных пути:
- использовать тип обертки, чтобы обернуть
std::pair
так что вы можете определитьoperator>>
в пространстве имен, связанных с этим типом оболочки - введите ваши операторы в пространство имен std (не рекомендуется??)