Почему 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 (либо с "старомодным" функтором, либо с лямбдой)
Другие вопросы по тегам