Overloading output stream operator for vector<T>
Solution 1
Did you actually try this code? It works fine on gcc with a small tweak std::vector<T>::const_iterator
, needs to be declared as typename std::vector<T>::const_iterator
You may be better off with using std::copy and std::ostream_iterator.
EDIT: types, dependent types and typename Can't fit it all in the comments, so here goes (btw. this is my understanding and I could be off by a country mile - if so please correct me!)...
I think this is best explained with a simple example..
Let's assume you have a function foo
template <typename T>
void foo()
{
T::bob * instofbob; // this is a dependent name (i.e. bob depends on T)
};
Looks okay, and typically you may do this
class SimpleClass
{
typedef int bob;
};
And call
foo<SimpleClass>(); // now we know that foo::instofbob is "int"
Again, seems self explanatory, however some nuser comes along and does this
class IdiotClass
{
static int bob;
};
Now
foo<IdiotClass>(); // oops,
What you have now is an expression (multiplication) as IdiotClass::bob resolves to a non-type!
To the human, it's obvious that this is stupid, but the compiler has no way of differentiating between types vs. non-types, and by default in C++ (and I think this is where compilers differ), all qualified dependent names (i.e. T::bob) will be treated as non-type. To explicitly tell the compiler that the dependent name is a real type, you must specify the typename
keyword -
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!)
};
This applies even if it is a typedef
. i.e.
template <typename T>
void foo()
{
typedef typename T::bob local_bob;
};
Is that any clearer?
Solution 2
This is what you want:
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;
}
You forgot the std:: on the first ostream
You put an extra space after [
in os << "["
.
and you need typename
before std::vector<T>::const_iterator
Solution 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;
}
Solution 4
this compile for me on visual studio 2003.
surely youshould use the keyword typename
before the const std::vector<T>
and I don't think the inline
keyword has sense, IMHO templates are really close to 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;
}
Edit: I have added a typename
also before the std::vector<T>::const_iterator
as Nim suggested
Related videos on Youtube
Comments
-
Leonid about 2 years
What is a recommended way to overload the output stream operator? The following can
notbe done. It is expected that compilation will fail if the operator << is not defined for a type 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: It does compile, the problem was unrelated and was in the namespace. Thanks for assistance.
-
Jeremy W. Murphy over 10 yearsCan you elaborate on the namespace problem and its solution? An overloaded function like this in the global namespace won't be found by ADL when the argument type is from std, and you can't put it in std. How did you solve it?
-
C.W. over 7 yearsC++11 syntax:
for (auto &i : vec) {}
make code shorter -
Walter over 7 years@Charles It should be
for(const auto&i:vec)
to compile.
-
-
smartnut007 over 13 yearscan someone tell me, why I cannot <pre><code> tag this piece of code ?
-
sbi over 13 yearsInlining is orthogonal to templatizing.
-
Leonid over 13 yearsThe template is declared in the header. If the header is included in multiple translational units there will be multiply defined symbols. Hence inline.
-
Jason Iverson over 13 yearsyou don't need to put typename in front of "const std::vector<T>& v"
-
Stephane Rolland over 13 yearsWith visual 2003 I didn't need none of the typename so as to compile. As it was a type dependent of T, I think it can please some other compiler to specify
typename
. -
Steve Jessop over 13 yearsbecause SO uses a modified version of "markdown". Indent by 4 spaces for formatted code.
-
Konrad Rudolph over 13 years@Stephane: no. Your first
typename
is actually an error and hence the code won’t work on other compilers either. You must only specifytypename
before dependent type names. And as sbi and Leonid have said,inline
is actually required here if this code is inside a header. -
Leonid over 13 yearsWhy would
std::copy
be a better way of streaming out in case of a generic vector? Withstd::copy
a dedicated long line should be written just to stream out a vector. However with output stream operator it is easier to do:std::cout << "Assignments = " << assignmentIds << std::endl;
. I would like to print a vector always inside braces"[" + vector + "]"
, and that would require one more line with just "]" ifstd::copy
is used. -
Leonid over 13 yearsIt does compile without typename after solving the original problem. Is there any use of specifying
typename
in this context even if it does compile apart from slight risk of having a misinterpreted type? -
Stephane Rolland over 13 years@Konrad, It DOES compile on VC2003. Maybe the VC compiler is wrong of course. But could you explain please WHY is it an error ? Why std::vector<T> is not a dependent name of T ? I would like to understand further.
-
Stephane Rolland over 13 years@Leonid, yes that would be great that someones explain the concept of dependent name.
-
Nim over 13 years@Leonid, in the case of the trivial vector example above, agreed the std::copy operation appears to be verbose, but consider now that you decide to change the formatting, and you want it to be separated by a ',' in some instances and by a ' ' in others, how would you have that with a single global operator<<? Now let's imagine that someone else is re-using your code, and wants to do something different? I'd be very wary of such global operators...
-
Nim over 13 years@Leonid, as to your second point, if your compiler is happy and you're happy that you're never going to have to re-compile your code in another compiler then I wouldn't bother; but for the sake of one key word "typename", if you are ever in the position of moving between compilers, you can save yourself some headache trying to understand the rather verbose compiler error messages you get as a result of leaving it out! It's your call...
-
Stephane Rolland over 13 years@Konrad, unless implicitely instanciated in a module/compilation unit, I conceive NO WAYS for a template not to be multiply defining symbols in each units. I mean it NO WAYS: Could you explain what the use of the keyword
inline
does for template. I personnaly call templates in headers inlined templates, this is why I think Inline and Templates are probably not Orthogonal... maybe not parralelle ;-) but not orthogonal. -
Inverse over 13 years
warning: signed in compared to unsigned int
:( -
sbi over 13 years@Leonid: Function templates must be defined in the header. Just as inlined functions, they won't cause a linker error, because the compiler is required to sort this out for you.
-
sbi over 13 years@Stephane: About 15 years after it has been thought up, VC still doesn't properly implement two-phase lookup. Don't rely on VC when it comes to where a
typename
(ortemplate
) is required. -
Konrad Rudolph over 13 years@Stephane: when it sees the code, the compiler knows that
vector<T>
is a type (it can’t be anything else here). However, wenn it seesvector<T>::something
it cannot assume thatsomething
is a type without knowing the type ofT
sincevector
may be specialized for a differentT
to contain e.g. a member function calledsomething
. See here: stackoverflow.com/questions/2487437/… – The VC++ compiler accepts this code because it’s just broken. -
sbi over 13 years@Stephane: Assuming your comment about inlining refers to me, not to Konrad:
inline
asks the compiler to substitute function calls with the actual code of the function called.template
doesn't do this. Of course, the compiler is free to inline or not no matter whether you asked it. Still, function templates do not need to be inlined. How the implementation deals with the resulting problem is their headache not yours. Many compilers will emit specially marked code for their instantiations that the linker then folds. -
Konrad Rudolph over 13 yearsAs for why
inline
is needed, consider you’ve got a header that is included in two different .cpp files. The header contains a non-inline functionfoo
. Now you compile both .cpp files and link them against each other (two objects to form one executable). Each of the .cpp files contains its own copy offoo
. When you link them together this will result in a “duplicate definition” error because the linker sees two identical definitions offoo
. And this behaviour is regardless of whether the function was actually a template. -
sbi over 13 years@Konrad: No, I think you're wrong here,
inline
is not needed. Templates ought to be in headers (except if usingexport
, which, sadly, is gone) and always needed to be. However, they do not need to beinline
. Your implementation will take care of that. Some implementations (I think cfront did that) defer template compilation until the link phase, others (I think VC does so) allow the linker to fold identical instantiations which resulted from instantiating the same template in multiple TUs. But __function templates do not need to beinline
and, TTBOMK, never needed to. -
Konrad Rudolph over 13 years@sbi: In this case I really am 100% sure that you are mistaken and that I’m correct. I’ve been involved in a generic library (SeqAn) for the past few years and this is one of the fundamental technical quirks we have to deal with. And as I’ve said, this is unrelated to templates: functions need to be declared
inline
in headers (and since templates need to be defined in headers, so do they). -
sbi over 13 years@Konrad: I can only believe that we have a serious misunderstanding here. In the last decade, I have probably written hundreds of function templates, very many of which I have not marked
inline
, all used across several compilers and a myriad of compiler versions. I have seen even more. The first thing I found wasboost/array.hpp
. It has the free function templatetemplate<class T, std::size_t N> bool operator== (const array<T,N>& x, const array<T,N>& y) {...}
(that's a very old version of boost, I came across, in case something has changed). Note the absence ofinline
. As I knew. -
Johannes Schaub - litb over 13 years@Konrad
inline
is not required for templates. The ODR allows to omit it. -
Johannes Schaub - litb over 13 years@Konrad the C++ Standard says "The keyword typename shall be applied only to qualified names, but those names need not be dependent.". C++03 in addition enforces "The keyword typename shall only be used in template declarations and definitions", but C++0x is going to remove that. That all said,
std::vector<T>
definitely is a dependent name. Still you don't needtypename
here, because the compiler can lookupstd::vector
at parse time and see that it is a class template (and thus know thatstd::vector<T>
is a type). -
Johannes Schaub - litb over 13 yearsWhat he actually wanted to write is
const typename ...
ortypename ... const
instead oftypename const ...
though, the last of which is syntactically illegal. -
Stephane Rolland over 13 years@Johannes Schaub thanks for your Expert clarifications. That was what I needed in our case. But however illegal
typename const
seems not to have offended much my VC2003 :-). I'll write things according Standard now :-) -
Konrad Rudolph over 13 years@Johannes:
vector<T>
may be a dependent name but it isn’t a qualified name. You not only don’t needtypename
here, it’s illegal (§14.6.5: “…typename
shall only be applied to qualified names”). And at leastg++
enforces this. But it’s true thattypename
can be applied to names that “need not be dependent”. – As for theinline
thing, wow. It actually works (again, ing++
) … the library has operated on false premises for years! Just for reference though, can you provide the section in the standard that allowsinline
to be omitted from function templates? I can’t find it. -
Johannes Schaub - litb over 13 years@Konrad
vector<T>
isn't qualified, butstd::vector<T>
is. For the inline thing, see 3.2 the bullet list at the very end (I don't have the standard here currently), mentioning among other things classes inline functions and also function/class templates. -
kirill_igum about 11 years<< is nice because it also works for vector<vector<vector<double>>> rather then writing 2 for_each/range loops
-
Tudax about 2 yearsA more modern way to do to this would be to use
for range loop
from C++ 11 instead ofconst_iterator
-
Tudax about 2 yearsYou add a
]
between each element