Перегрузка оператора выходного потока для вектора <T>

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

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;
}

EDIT: он компилируется, проблема не связана и находится в пространстве имен. Спасибо за помощь.

Ответы

Ответ 1

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

Вам может быть лучше с помощью std:: copy и std:: ostream_iterator.

EDIT: типы, зависимые типы и typename Не могу вместить все это в комментарии, так что вот здесь (кстати, это мое понимание, и я мог бы уехать на одну милю - если так, пожалуйста, исправьте меня!)...

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

Предположим, что у вас есть функция 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 разрешает не-тип!

Для человека очевидно, что это глупо, но компилятор не имеет возможности различать типы по сравнению с не-типами, а по умолчанию - в С++ (и я думаю, что это то, где компиляторы отличаются), все квалифицированные зависимые имена (т.е. 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

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

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;
}

Вы забыли std:: при первом ostream

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

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

Ответ 3

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;
}

Ответ 4

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

#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, как предложил Ним