Mail Archives: djgpp/2001/10/08/10:34:25
Traveler wrote:
>
> > > for(unsigned long index = 0;index < length;index++)
> > > output << '[' << table[index] << ']';
> >
> > Hmm - I'm not sure I want array elements shown inside [].
> > A more logical way to do it is to separate them by ", ".
>
> Thatīs the matter of taste. Also explain in as shortly as possible the term "logical" :)
A logical view of an array would be a group or list of items.
Showing that group/list as each item separated by the list
separator (usually , or ; - depending on your locale)
therefore seems a logical way of doing things.
> Yes, you can. The problem is that when you try to cout arrays of characters (and thatīs what the strings are...)
> the result is not what you want....
>
> char string [] = {"God created C++"};
>
> cout << string << endl; // [G][o][d][ ][c][r][e][a][t][e][d][ ][C][+][+][ ]
Which is why God saw fit to create partial specialization
as well.
In the case above, you merely need:
// Basic case
template <typename T, size_t N>
ostream&
operator<<(ostream& out, T (&array)[N])
{
for (size_t i = 0; i < n; ++i) {
if (i > 0)
out << ", ";
out << array[i];
}
out.flush();
}
// Special case for 'strings'
template <size_t N>
ostream&
operator<<(ostream& out, char (&array)[N])
{
for (size_t i = 0; i < n; ++i)
out << array[i];
out.flush();
}
Since a concrete match is always better than a template, the compiler
will use the second version for character arrays. (Note: since this
is a function template, the second form has to be a new template, as
function templates can't be partially specialized).
> Vectors, vectors, vectors....
> Letīs say we have declared a trivial class "A" and it has member "_x" and the
> only thing besides the normal constructor(s) & destructor is conversion function
> that outputs in this case "_x".
Disclaimer: conversion operators are generally regarded as Evil(tm).
> The "cout" without vector version does work but will the vector version work ?
Sure it will.
-- foo.cc
#include <vector>
#include <iostream>
using namespace std;
template <typename T, typename A>
std::ostream&
operator<<(std::ostream& out, const std::vector<T, A>& array)
{
std::vector<T, A>::const_iterator first = array.begin();
std::vector<T, A>::const_iterator last = array.end();
std::vector<T, A>::const_iterator i;
for (i = first; i != last; ++i) {
if (i != first)
out << ", ";
out << (*i);
}
out.flush();
}
template <typename A>
std::ostream&
operator<<(std::ostream& out, const std::vector<char, A>& array)
{
std::vector<char, A>::const_iterator first = array.begin();
std::vector<char, A>::const_iterator last = array.end();
std::vector<char, A>::const_iterator i;
for (i = first; i != last; ++i)
out << (*i);
out.flush();
}
class A
{
int _x;
public:
A(int x) : _x(x) {}
operator int() const { return this->_x; }
};
int
main(void)
{
vector<A> table;
table.push_back(A(10));
table.push_back(A(15));
cout << table << endl;
vector<char> str;
str.push_back('D');
str.push_back('J');
str.push_back('G');
str.push_back('P');
str.push_back('P');
cout << str << endl;
return 0;
}
--end of foo.cc
> Also, I can understand that in your vesrion the type "T" is the table element
> type but what is the type "A" in your version ???
> ( template <typename T, typename A>)
std::vector takes two template arguments; the first (T here) is the type
of the
elements, the second (A) is the type of the allocator object to use.
Since the
second argument is defaulted, it may not be necessary to include it in
the
derived ostream operator at all.
- Raw text -