Перегрузка оператора выходного потока для вектора <T> - PullRequest
15 голосов
/ 02 ноября 2010

Каков рекомендуемый способ перегрузки оператора выходного потока?Следующее может не быть выполнено.Ожидается, что компиляция не удастся, если оператор << не определен для типа T. </p>

template < class T >
inline std::ostream& operator << (std::ostream& os, const std::vector<T>& v) 
{
    os << "[";
    for (std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii)
    {
        os << " " << *ii;
    }
    os << " ]";
    return os;
}

РЕДАКТИРОВАТЬ: он компилируется, проблема не связана и была в пространстве имен.Спасибо за помощь.

Ответы [ 4 ]

10 голосов
/ 02 ноября 2010

Это то, что вы хотите:

template < class T >
std::ostream& operator << (std::ostream& os, const std::vector<T>& v) 
{
    os << "[";
    for (typename std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii)
    {
        os << " " << *ii;
    }
    os << "]";
    return os;
}

Вы забыли стандартный номер :: на первом ostream

Вы ставите дополнительный пробел после [ в os << "[".

и вам нужно typename до std::vector<T>::const_iterator

7 голосов
/ 02 ноября 2010

Вы действительно пробовали этот код?Он отлично работает на gcc с небольшой настройкой std::vector<T>::const_iterator, его необходимо объявить как typename std::vector<T>::const_iterator

. Возможно, вам лучше использовать std :: copy и std :: ostream_iterator.

РЕДАКТИРОВАТЬ: типы, зависимые типы и имя типа Не может вместить все это в комментариях, так что здесь (кстати, это мое понимание, и я мог бы быть на милю страны - если так, пожалуйста, поправьте меня!) ...

Я думаю, это лучше всего объяснить на простом примере ..

Предположим, у вас есть функция foo

template <typename T>
void foo()
{
  T::bob * instofbob; // this is a dependent name (i.e. bob depends on T)
};

Выглядит хорошо, и обычно выможет сделать это

class SimpleClass
{
  typedef int bob;
};

и позвонить

foo<SimpleClass>(); // now we know that foo::instofbob is "int"

Опять же, кажется самоочевидным, однако приходит какой-то nuser и делает это

class IdiotClass
{
  static int bob;
};

Теперь

foo<IdiotClass>(); // oops, 

Теперь у вас есть выражение (умножение), поскольку IdiotClass :: bob преобразуется в нетип!

Для человека очевидно, что это глупо, но компилятор не имеетспособ отличить типы от не-типов, и по умолчанию в C ++ (и я думаю, что это гдеразличаются), все квалифицированные зависимые имена (т. е. T :: bob) будут обрабатываться как не тип .Чтобы явно сообщить компилятору, что зависимое имя является вещественным типом, необходимо указать ключевое слово typename -

template <typename T>
void foo()
{
  typedef typename T::bob *instofbob; // now compiler is happy, it knows to interpret "bob" as a type (and will complain otherwise!)
};

Это применимо, даже если это typedef.то есть

template <typename T>
void foo()
{
  typedef typename T::bob local_bob;
};

Это понятнее?

2 голосов
/ 02 ноября 2010
template<typename T>
std::ostream& operator<<(std::ostream& s, std::vector<T> t) { 
    s << "[";
    for (std::size_t i = 0; i < t.size(); i++) {
        s << t[i] << (i == t.size() - 1 ? "" : ",");
    }
    return s << "]" << std::endl;
}
1 голос
/ 02 ноября 2010

этот компилятор для меня на Visual Studio 2003. Конечно, вы должны использовать ключевое слово typename перед const std::vector<T>, и я не думаю, что ключевое слово inline имеет смысл, шаблоны IMHO действительно близки к вставке.

#include <ostream>
#include <vector>
#include <iostream>

template < class T >
std::ostream& operator << (std::ostream& os, typename const std::vector<T>& v) 
{
    os << "[ ";
    for (typename std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii)
    {
        os << " " << *ii;
    }
    os << "]";
    return os;
}

void Test()
{
    std::vector<int> vect;
    vect.push_back(5);
    std::cerr << vect;
}

Редактировать: я добавил typename также перед std::vector<T>::const_iterator, как предложил Ним

...