Почему ostream_iterator работает не так, как ожидалось?
Излишне говорить больше, чем следующий код:
#include <utility>
#include <vector>
#include <iostream>
#include <iterator>
using namespace std;
typedef pair<char, char> PAIR;
ostream& operator <<(ostream& os, const PAIR& r)
{
return os << r.first;
}
int main()
{
vector<PAIR> coll;
cout << coll[0]; // OK.
// The following line will cause a compilation error! Why???
copy(coll.begin(), coll.end(), ostream_iterator<PAIR>(cout));
}
Ответы
Ответ 1
Проблема заключается в том, что поиск по имени не находит ваш operator<<(ostream& os, const PAIR& r)
. Код, который пытается вызвать operator<<
, находится где-то внутри ostream_iterator<>
, который сам находится внутри пространства имен std
. Поиск имени просматривает правильную функцию внутри ostream_iterator<>
и пространства имен std
; зависимый от аргумента поиск не помогает здесь, потому что оба параметра также находятся в пространстве имен std
.
Итак, мое предложение: (1) либо обернуть оператора в namespace std { }
, но это UB, IIRC. Или (2) создайте структуру, наследующую от std::pair
, чтобы определить новый тип в вашем пространстве имен и используя ADL, чтобы найти ваш operator<<()
.
UPDATE:
Мое третье предложение - использовать пользовательский манипулятор для печати пары.
Что касается моего второго предложения, если вы можете использовать С++ 11, наследование от std::pair
должно быть простым (непроверенным):
struct PAIR : std::pair
{
using std::pair::pair;
};
Если вы не можете использовать С++ 11, я предлагаю использовать настраиваемый манипулятор.
Ответ 2
Это обычная проблема: одним словом, ваш operator<<
не отображается при создании экземпляра std::ostream_iterator
.
Во время экземпляра поиск имени пытается найти operator<<
в пространстве имен std
. Кандидаты будут найдены, поэтому никакие другие пространства имен не будут рассмотрены (и, в частности, не глобальное пространство имен). Затем вступает в действие разрешение перегрузки: ни одна из перегрузок не соответствует типу аргумента, поэтому компиляция не выполняется. Обратите внимание, что поиск зависимых от аргументов здесь не помогает, так как std::pair
также находится в пространстве имен std
.
У вас есть два решения:
- Включите
operator<<
в namespace std { }
, хотя вы должны знать, что это незаконно в соответствии со стандартом (17.4.3.1)
- Избегайте
std::copy
для этой задачи и используйте std::for_each
(либо с помощью "старомодного" функтора, либо лямбда)