Почему ostream_iterator не работает должным образом? - PullRequest
10 голосов
/ 15 декабря 2010

Излишне говорить больше, чем следующий код:

#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 ]

9 голосов
/ 15 декабря 2010

Проблема в том, что поиск имени не находит ваш operator<<(ostream& os, const PAIR& r).Код, который пытается вызвать operator<<, находится где-то внутри ostream_iterator<>, которое находится внутри пространства имен std.Поиск имени ищет правильную функцию внутри ostream_iterator<> и пространства имен std;зависимый от аргумента поиск здесь не помогает, потому что оба параметра также находятся в пространстве имен std.

Итак, я предлагаю (1) либо заключить ваш оператор в namespace std { }, но этоUB, IIRC.Или (2) создайте структуру, унаследованную от std::pair, чтобы определить новый тип в вашем пространстве имен, и с помощью ADL найдите ваш operator<<().

ОБНОВЛЕНИЕ:

Мое третье предложение - использовать пользовательский манипулятор для распечатки пары.

Что касается моего 2-го предложения, если вы можете использовать C ++ 11, наследование от std::pair должно быть простым (не проверено):

struct PAIR : std::pair
{
  using std::pair::pair;
};

Если вы не можете использовать C ++ 11, тогда я предлагаю использовать пользовательский манипулятор.

9 голосов
/ 15 декабря 2010

Это распространенная проблема: одним словом, ваш operator<< не виден при создании экземпляра std::ostream_iterator.

Во время создания экземпляра поиск имени пытается найти operator<< в пространстве имен std,Будут найдены кандидаты, поэтому другие пространства имен рассматриваться не будут (и, в частности, не глобальное пространство имен).Затем вступает в силу разрешение перегрузки: ни одна из перегрузок не соответствует типу аргумента, поэтому компиляция не удалась.Обратите внимание, что поиск в зависимости от аргумента здесь не поможет, так как std::pair также находится в пространстве имен std.

У вас есть два решения:

  • Вложите operator<< в namespace std { }, хотя вы должны знать, что это недопустимо в соответствии со стандартом (17.4.3.1)
  • Избегайте std::copy для этой задачи и используйте std::for_each (либо со «старым»Функтор или лямбда)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...