Как я могу распечатать содержимое любого контейнера в общем виде? - PullRequest
9 голосов
/ 20 июля 2009

Я пытаюсь написать кусок кода для развлечения, используя шаблоны C ++.

#include <iostream>
#include <vector>

template <class Container>
std::ostream& operator<<(std::ostream& o, const Container& container)
{
    typename Container::const_iterator beg = container.begin();

    o << "["; // 1

    while(beg != container.end())
    {
        o << " " << *beg++; // 2
    }

    o << " ]"; // 3

    return o;
}

int main()
{
    std::vector<int> list;

    list.push_back(0);
    list.push_back(0);

    std::cout << list;

    return 0;
}

Приведенный выше код не компилируется:)

При 1, 2, 3 выдается та же ошибка: ошибка C2593: 'operator <<' является неоднозначным </strong>

Все, что я пытаюсь сделать, это перегрузить оператор << для работы с любым контейнером. Имеет ли это смысл ? Как это будет сделано, если возможно, если нет, то почему? </p>

РЕДАКТИРОВАТЬ :: Спасибо за исправления :) 'sth' - хорошее решение.

Мне просто любопытно, исчезнет ли эта двусмысленность, как объяснил Нейл, если мы сможем использовать C ++ 0x Concepts?

Ответы [ 7 ]

7 голосов
/ 20 июля 2009

Вы можете ограничить свой оператор << только для шаблонных контейнеров, указав, что параметр шаблона контейнера сам по себе является шаблонным.Поскольку стандартные контейнеры C ++ также имеют параметр шаблона распределителя, вы также должны включить его в качестве параметра шаблона контейнера. </p>

template
    < typename T
    , template<typename ELEM, typename ALLOC=std::allocator<ELEM> > class Container
    >
std::ostream& operator<< (std::ostream& o, const Container<T>& container)
{
    typename Container<T>::const_iterator beg = container.begin();

    o << "["; // 1

    while(beg != container.end())
    {
        o << " " << *beg++; // 2
    }

    o << " ]"; // 3

    return o;
}

int main()
{
    std::vector<int> list;

    list.push_back(0);
    list.push_back(0);

    std::cout << list;

    return 0;
}
4 голосов
/ 20 июля 2009

Ваш недавно определенный operator<< не только соответствует контейнерам, но также и любым другим типам, таким как int и строки. Вот почему компилятор жалуется на неоднозначности, когда ему нужно найти соответствующий operator<< для вывода "[".

Один из способов обойти эту проблему - переименовать вашу функцию вывода:

template <class Container>
std::ostream& container_out(std::ostream& o, const Container &container) {
  // ...
}

Затем вы можете добавить простые оболочки, чтобы включить operator<< для всех контейнеров, которые вы хотите напечатать:

template<typename T>
std::ostream& operator<<(std::ostream& o, const std::vector<T> &container) {
  return container_out(o, container);
}

template<typename T>
std::ostream& operator<<(std::ostream& o, const std::map<T> &container) {
  return container_out(o, container);
}
3 голосов
/ 20 июля 2009

В чем ошибка? Я видел один, вам нужно имя:

typename Container::iterator beg = container.begin();

Что здесь происходит, так это то, что компилятор ничего не знает о контейнере, когда он впервые читает его. Поэтому нам нужно немного помочь и сказать, что итератор будет типом (синтаксически это может быть любое допустимое имя в области видимости класса, поэтому функция, переменная, ...). При написании метода шаблона любой тип, который зависит от типа шаблона, должен указывать, что это тип с ключевым словом typename.

2 голосов
/ 20 июля 2009

Ваш оператор вносит свою двусмысленность - он сам может быть использован для печати того, что он пытается напечатать. Мой совет:

  • использовать именованную функцию, а не оператор
  • передать контейнер по константной ссылке (однако это не связано с проблемой)
1 голос
/ 20 июля 2009

Может быть, не такой общий, как то, что вы публикуете (вам нужно передать содержащийся тип), а также оставляет дополнительный разделитель в конце, но вы можете использовать STL для этого:

std::vector<int> v;
v.push_back( 10 );
v.push_back( 20 );

std::cout << "[";
std::copy( v.begin(), v.end(), std::ostream_iterator<int>( std::cout, " " ) );
std::cout << "]";

Будет выводить:

[10 20]

Обратите внимание, что дополнительный разделитель находится в конце последовательности и что между [и первым элементом нет начального пробела.

1 голос
/ 20 июля 2009

Хорошо, теперь ваш шаблон вызывает путаницу. Компилятор не может выбирать между вашим оператором и тем, кого вы ожидаете.

0 голосов
/ 16 февраля 2014

http://blog.csdn.net/cqdjyy01234/article/details/19234329 может быть хорошим решением. Работает для контейнеров STL и массива в стиле C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...