Перегрузка оператора выходного потока для вектора <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
, как предложил Ним