Почему 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));
}
2 ответа
Проблема в том, что поиск имени не находит ваш operator<<(ostream& os, const PAIR& r)
, Код, который пытается вызвать operator<<
находится где-то внутри ostream_iterator<>
который сам внутри std
Пространство имен. Поиск имени ищет правильную функцию внутри ostream_iterator<>
и std
Пространство имен; зависимый от аргумента поиск здесь не помогает, потому что оба параметра находятся в std
пространство имен тоже.
Таким образом, я предлагаю (1) либо обернуть вашего оператора в namespace std { }
, но это UB, IIRC. Или (2) создать структуру, наследующую от std::pair
определить новый тип в вашем пространстве имен и с помощью ADL найти ваш operator<<()
,
ОБНОВИТЬ:
Мое третье предложение - использовать собственный манипулятор для распечатки пары.
Что касается моего второго предложения, если вы можете использовать C++11, наследуя от std::pair
должно быть легко (не проверено):
struct PAIR : std::pair
{
using std::pair::pair;
};
Если вы не можете использовать C++11, то я предлагаю использовать пользовательский манипулятор.
Это общая проблема: одним словом, ваш operator<<
не видно при создании экземпляра std::ostream_iterator
,
Во время создания экземпляра поиск имени пытается найти operator<<
в пространстве имен std
, Будут найдены кандидаты, поэтому другие пространства имен не будут рассматриваться (и, в частности, не глобальное пространство имен). Затем вступает в силу разрешение перегрузки: ни одна из перегрузок не соответствует типу аргумента, поэтому компиляция не удалась. Обратите внимание, что поиск, зависящий от аргумента, здесь не поможет, так как std::pair
также находится в пространстве имен std
,
У вас есть два решения:
- Вложите свой
operator<<
вnamespace std { }
, хотя вы должны знать, что это незаконно согласно стандарту (17.4.3.1) - избежать
std::copy
для этой задачи и использованияstd::for_each
(либо с "старомодным" функтором, либо с лямбдой)