2012-05-08 2 views
4

Пожалуйста, учитывайте следующий код. Я пытаюсь вывести вектор векторов в ostream.Печать вектор векторов для ostream

#include <iterator> 
#include <iostream> 
#include <string> 
#include <vector> 
#include <algorithm> 

template<typename T> 
std::ostream &operator <<(std::ostream &os, const std::vector<T> &v) { 
    using namespace std; 
    copy(v.begin(), v.end(), ostream_iterator<T>(os, "\n")); 
    return os; 
} 

int main() { 
    using namespace std; 
    vector<string> v1; 
    cout << v1; 
    vector<vector<string> > v2; 
    cout << v2; 
    return 0; 
} 

Утверждение, в котором я вывожу вектор строк. Тот, где я вывожу вектор векторов строк, не имеет. Я использую g ++ 4.7.0. Я пробовал w/& без флага -std = C++ 11. В режиме C++ 11 он дает мне эту строку на половине страницы ошибок.

error: cannot bind 'std::ostream_iterator<std::vector<std::basic_string<char> >, char, std::char_traits<char> >::ostream_type {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&' 

Я не думаю, что понимаю, что это значит. Может ли кто-нибудь объяснить мне? Я более или менее знаю, что такое ссылка rvalue, но я не понимаю, почему std::basic_ostream<char> не связывается с std::basic_ostream<char>&&. Может быть, я не знаю этого достаточно хорошо. И есть ли лучший способ сделать это?

Заранее спасибо.

+0

подумайте об этом, в 'vector >' case, "\ n" должны быть закрыты для 'vector '. Потому что это не сработает –

+0

@ J-16SDiZ: О чем ты говоришь? Нет, нет. –

+0

@ J-16SDiZ: Нет. Это просто неправильно. – Nawaz

ответ

8

ошибка вы получаете, немного вводить в заблуждение. Когда я пытался скомпилировать программу, которую я должен был вырыть в шаблоне рвоту совсем немного, и я закончил тем, что я думал, что происходит:

error: no match for 'operator<<' in '*((std::ostream_iterator<std::vector<std::basic_string<char> >, char, std::char_traits<char> >*)this)->std::ostream_iterator<std::vector<std::basic_string<char> >, char, std::char_traits<char> >::_M_stream << __value' 

В основном, когда вы назвали алгоритм копирования, он используется выходной итератор, который использовал оператор < < из пространства имен std. После этого поиск проверяет, что он пытается найти перегрузку для вектора шаблона <> в пространстве имен std (потому что именно там находится ИТ).

Так что вам нужно сделать, это объявить оператора потока для векторного шаблона в пространстве имен std. Обогните свой код namespace std {} и посмотрите, что произойдет ...

Следует отметить, что то, что вы делаете, в основном изменяет std :: vector <> и добавляет к нему поведение, которого раньше не было. Выполнение этого является нестандартным, неопределенным и может легко мешать вам. Вы можете рассмотреть другие варианты.


Я был неправ об этом, являющемся предметом поиска koenig.Это не так, проблема заключается в сокрытии имени, аналогичном тому, что происходит в классах, здесь вы объявляете перегрузку чего-либо в базе (а не переопределяете).

Стандартное пространство имен объявляет несколько операторов «< <». Это в основном функции с именем operator <<. По сути то, что у вас есть это:

void fun(int); 

namespace Test { 

    void fun() { fun(3); } 

} 

int main() { 
    Test::fun(); 
} 

Обратите внимание, что вы можете использовать fun(int) из глобального пространства имен или любого пространства имен, которое не имеет какой-либо функции с именем fun в нем. Вы не можете использовать его из пространства имен Test.

Именно поэтому использование вами оператора < <, объявленного глобально, отлично работает из глобального пространства имен, но не из пространства имен std. Пространство имен std уже имеет то же имя, что и перегрузка, которую вы пытаетесь предоставить, и поэтому перегрузка скрыта от всех вещей в пределах std. Если бы вы могли использовать декларацию использования, все было бы по-другому.

+0

Помещение вещей в пространство имен std, которое запрещено стандартом, так ли? Несмотря на это, я очень сомневаюсь, что это действительно вызовет проблему в любой реальной реализации, и, похоже, это работает для меня. –

+0

Да, это сработало! Благодаря! Я не совсем понимаю, хотя. Если он может найти перегрузку для вектора , где T является строкой, в глобальном пространстве имен, почему он не может найти перегрузку на втором уровне двухуровневого поиска? Является ли код выходного итератора в пространстве имен std, написанным для поиска std :: operator < Ashley

+0

Это неопределенное поведение, но вы должны делать то, что вам нужно. Если бы это было определено уже, это уже сработало бы. –

4

Вам нужна эта утилита библиотека:


Если вы хотите сделать это самостоятельно (так, чтобы научить себя), то вам необходимо определить две перегрузки, как:

  • std::vector<T>:

    template<typename T> 
    std::ostream &operator <<(std::ostream &os, const std::vector<T> &v) { 
        using namespace std; 
        copy(v.begin(), v.end(), ostream_iterator<T>(os, "\n")); 
        return os; 
    } 
    
  • std::vector<std::vector<T>> Для:

    template<typename T> 
    std::ostream &operator <<(std::ostream &os, const std::vector<std::vector<T>> &v) { 
        using namespace std; 
    
        //NOTE: for some reason std::copy doesn't work here, so I use manual loop 
        //copy(v.begin(), v.end(), ostream_iterator<std::vector<T>>(os, "\n")); 
    
        for(size_t i = 0 ; i < v.size(); ++i) 
         os << v[i] << "\n"; 
        return os; 
    } 
    

Если у вас есть эти перегруженные, то они вместе будут обрабатывать эти случаи рекурсивно:

std::vector<int> v; 
std::vector<std::vector<int>> vv; 
std::vector<std::vector<std::vector<int>>> vvv; 
std::vector<std::vector<std::vector<std::vector<int>>>> vvvv; 

std::cout << v << std::endl; //ok 
std::cout << vv << std::endl; //ok 
std::cout << vvv << std::endl; //ok 
std::cout << vvvv << std::endl; //ok 
+0

Есть ли что-то еще, что вы делаете, чтобы заставить это работать? Потому что это не работает для меня. http://ideone.com/A2d67 –

+1

@BenjaminLindley: Я не вижу причин, почему это не должно работать. Может быть, ошибка компилятора? Во всяком случае, ручной цикл работает отлично. – Nawaz

+0

Другая версия не работает, поскольку 'ostream_iterator' находится в пространстве имен' std', как и 'vector'. Таким образом, ADL не находит шаблон 'operator <<', который вы определили, и он не компилируется. –

Смежные вопросы