Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Problems deriving from std::ostringstream

Reply
Thread Tools

Problems deriving from std::ostringstream

 
 
Adrian
Guest
Posts: n/a
 
      05-08-2009
Hi all,

I am having some problems deriving a logging class from
std::stringstream and I dont understand why it is not work. Main goal
of this I am trying to replace 1000's of lines in some old code that
is of the style
Lock();
stream << "some message";
Unlock();

Main questions are:
1. Why does the temporary version not work with class Wibble (compiler
cannot match an operator<< func)
2. Why does the temporary version output address of char * rather then
the string

Do I need to add operator<< for all the standard types?

[Output]
dluadrianc:/home/adrianc> g++ -g -Wall -ansi -pedantic -Wextra log.cc
dluadrianc:/home/adrianc> a.out
try char* apple try int 23
BEGIN
23
I am wibbles output friend
This is a test
END
BEGIN
42
0x8049540
END

//code
//#include <pthread.h>
#include <iostream>
#include <cstdio>
#include <sstream>
#include <cstdarg>

class LockedLog
{
public:
static LockedLog &Instance()
{
if(instance==0)
{
instance=new LockedLog();
}
return *instance;
}
void log(const char *fmt, ...) //__attribute__((format(printf,
2,3)))
{
va_list ap;
va_start(ap, fmt);
// pthread_mutex_lock(&m_LogMutex);
vprintf(fmt, ap);
// pthread_mutex_unlock(&m_LogMutex);
va_end(ap);
}
private:
LockedLog() { /*pthread_mutex_init(&m_LogMutex, 0);*/ }
static LockedLog *instance;
pthread_mutex_t m_LogMutex;
};

class LogStreamer : public std:stringstream
{
public:
LogStreamer() :m_logger(LockedLog::Instance()) {}
~LogStreamer()
{
m_logger.log("%s", str().c_str());
}
private:
LockedLog &m_logger;
};

LockedLog *LockedLog::instance=0;

class Wibble
{
public:
friend std:stream &operator<<(std:stream &os, const Wibble
&) { os << "I am wibbles output friend"; return os; }
};

int main(int, char *[])
{
LockedLog::Instance().log("try char* %s try int %d\n", "apple",
23);

std::cout << "BEGIN\n";
{
LogStreamer strm;
strm << 23 << std::endl;
strm << Wibble() << std::endl;
strm << "This is a test" << std::endl;
}
std::cout << "END\n";

std::cout << "BEGIN\n";
LogStreamer() << 42 << std::endl;
// doesnt compile
// LogStreamer() << Wibble() << std::endl;
LogStreamer() << "This is NOT a test" << std::endl;
std::cout << "END\n";

return 0;
}

 
Reply With Quote
 
 
 
 
James Kanze
Guest
Posts: n/a
 
      05-09-2009
On May 8, 4:57 pm, Adrian <(E-Mail Removed)> wrote:

> I am having some problems deriving a logging class from
> std::stringstream and I dont understand why it is not work.
> Main goal of this I am trying to replace 1000's of lines in
> some old code that is of the style
> Lock();
> stream << "some message";
> Unlock();


> Main questions are:
> 1. Why does the temporary version not work with class Wibble
> (compiler cannot match an operator<< func)
> 2. Why does the temporary version output address of char *
> rather then the string


The short answer is that the standard streams have identity, and
are not designed to be used as temporary objects. What you need
is a wrapper or handle class which contains a pointer to the
stream and overloads all of the operators.

The literal answer is that some of the operator<< functions are
members, others free functions which take a non-const reference
to the stream as the first argument. Since you can't bind a
temporary to a non-const reference, only the first are taken
into consideration in overload resolution, which leads to some
surprises: the overloads for integral and floating point types
are not members, so aren't found (and result in a compiler
error), and the overload for void* is a member, but the one for
char* isn't, so a string literal finds the first (because of the
implicit conversion of any pointer type to void*), rather than
the second.

Note that this problem only affects the first operation; the
return value of all of the << operators is an ostream&, which
will bind to the ostream&. For a single instance, the simplest
solution is to do something like:

StreamType().flush() << ...

(Traditionally, StreamType() << "" was used, but the standards
committee changed the << operator for char const* from a member
to a free function.)

> Do I need to add operator<< for all the standard types?


No. You need a class which doesn't derive from an ostream, but
rather contains a reference to one, and defines all of the <<
operators (by means of a simple template) to the stream it
refers to. If the temporary might be copied (usually the case),
you probably need some sort of reference counting to ensure that
the real "disposal" only occurs when the last instance is
destructed, see OutputStreamWrapper in the IO subsystem at
http://kanze.james.neuf.fr/code-en.html.

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
 
 
 
Bart van Ingen Schenau
Guest
Posts: n/a
 
      05-09-2009
Adrian wrote:

> Hi all,
>
> I am having some problems deriving a logging class from
> std::stringstream and I dont understand why it is not work. Main goal
> of this I am trying to replace 1000's of lines in some old code that
> is of the style
> Lock();
> stream << "some message";
> Unlock();
>
> Main questions are:
> 1. Why does the temporary version not work with class Wibble (compiler
> cannot match an operator<< func)
> 2. Why does the temporary version output address of char * rather then
> the string


Both questions have the same answer: For both Wibble and char*, the
temporary LogStreamer() object can not bind to the first argument of the
respective operator<< overloads. The reason is that both overloads take
a non-const reference to an ostream, and the language does not allow
binding a temporary object to a non-const reference.
The reason that outputting an integer and an address DO work is because
those operator<< overloads are defined as members of the class ostream,
and the standard does allow you to call a member function on a temporary
object.

>
> Do I need to add operator<< for all the standard types?


No, because that will not help you with user-defined types like Wibble.

Here is an implementation of LogStreamer that can be used like you want
it:

class LogStreamer
{
public:
LogStreamer() :m_logger(LockedLog::Instance()) {}
~LogStreamer()
{
m_logger.log("%s", oss.str().c_str());
}

template<typename T>
std:stream& operator<<(const T& rhs)
{
return oss << rhs;
}

private:
LockedLog &m_logger;
std:stringstream oss;
};

The trick is in the templated operator<<.
As this is a member function, it can be called on a temporary object.
As it returns a reference (which is *never* considered a temporary
object), you can chain it in the normal way for generating output
without problems.

There is one caveat: This template does not work for manipulators, like
std::endl. If you want to be able to stream those *as the first item*
into a LogStreamer, you will need additional overloads of the
LogStreamer:perator<<.

Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/

 
Reply With Quote
 
Adrian
Guest
Posts: n/a
 
      05-11-2009
On May 9, 5:51*am, Bart van Ingen Schenau <(E-Mail Removed)>
wrote:

Thank you and James for the answers provided. It makes sense now and
code works great.

Thanks again.

Adrian
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
problems referencing form elements by deriving their name from the value of another element libsfan01 Javascript 2 07-13-2006 09:32 PM
Deriving from MembershipUser and ASPNET Config Tool Mark Olbert ASP .Net 9 01-20-2006 07:59 AM
Problem deriving from WebControl Class Gary Rynearson ASP .Net 0 11-18-2005 03:34 PM
deriving from textbox control Lisa Calla ASP .Net 3 10-22-2004 06:16 PM
Problem in deriving custome class from XmlNode Mahesh Devjibhai Dhola ASP .Net 0 10-15-2004 07:38 AM



Advertisments