delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2001/10/08/10:34:25

Message-ID: <3BC1B4F3.A2108146@falconsoft.be>
Date: Mon, 08 Oct 2001 16:15:15 +0200
From: Tim Van Holder <tim DOT vanholder AT falconsoft DOT be>
Organization: Anubex (www.anubex.com)
X-Mailer: Mozilla 4.78 [en] (X11; U; Linux 2.2.16-3 i686)
X-Accept-Language: en, nl-BE, nl
MIME-Version: 1.0
Newsgroups: comp.lang.c++,comp.os.msdos.djgpp
Subject: Re: More out from "cout"....
References: <9pque5$eui$1 AT tron DOT sci DOT fi> <3BC16F90 DOT A6FE66E3 AT falconsoft DOT be> <9ps3vh$do$1 AT tron DOT sci DOT fi>
Lines: 137
NNTP-Posting-Host: 194.78.64.238
X-Trace: 1002550577 reader1.news.skynet.be 36470 194.78.64.238
X-Complaints-To: abuse AT skynet DOT be
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp
Reply-To: djgpp AT delorie DOT com

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 -


  webmaster     delorie software   privacy  
  Copyright Đ 2019   by DJ Delorie     Updated Jul 2019