Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Deriving my own stream class

Reply
Thread Tools

Deriving my own stream class

 
 
Dan Smithers
Guest
Posts: n/a
 
      06-17-2008
I want to write my own class derived from the ostream class.

I have been getting errors with my templates:

First, I get an error writing a nested template. If I leave the function
definition inside template class definition (commented out at //1) then
it compiles and runs fine, but if I declare and define the function
separately (at //2).

Is the following syntax supported by g++?
template<typename charT, typename Traits>
template<typename T>
as I get the compiler error
"mystream.cpp:47: error: too many template-parameter-lists"

I can't get the use_facet command to work (commented out at //3) as I no
longer have visibility of ostr for getloc and can't call it on my
derived class. Is there another way of achieving this?

I can't get the manipulator function / object combination to compile.
"mystream_test.cpp:11: error: no matching function for call to
‘setfmt(const char [6])’"
Do I need to explicitly qualify the template?

Finally, the compiler seems to get confused by the output operator in
the manipulator (at //4) and issues the following warning:
"mystream.h:41: warning: friend declaration ‘Ostream&
operator<<(Ostream&, const osmanip<Ostream, Arg>&)’ declares a
non-template function
mystream.h:41: warning: (if this is not what you intended, make sure the
function template has already been declared and add <> after the
function name here) -Wno-non-template-friend disables this warning"

Are these problems due to my own misunderstanding of templates?

thanks

dan

I have written my templates in three file (mystream.h, mystream.cpp and
mystream_test.cpp) and compiling with g++ 4.2.3

// mystream.h
#include <iostream>
#ifndef __MY_STREAM_H
#define __MY_STREAM_H

template <typename charT, typename Traits=std::char_traits<charT> >
class CMyStream : virtual public std::basic_ostream<charT, Traits>
{
public:
charT *m_fmt;

public:
// constructor
CMyStream(std::basic_ostream<charT, Traits>& ostr, const char *fmt);
// destructor
~CMyStream();
// change format string
std::basic_ostream<charT, Traits>& format(const char *fmt);
// retrieve format string
charT *format() const;

// output operator
template<typename T>
friend CMyStream& operator<<(CMyStream& ostr, T val); //1
// {
// (std::basic_ostream<charT, Traits>&)ostr << ostr.m_fmt << " ";
// (std::basic_ostream<charT, Traits>&)ostr << val;
// }

};

template <class Ostream, class Arg>
class osmanip {
public:
osmanip(Ostream& (*pf)(Ostream&, Arg), Arg arg);

protected:
Ostream& (*pf_)(Ostream&, Arg);
Arg arg_;

friend Ostream&
operator<< (Ostream& ostr, const osmanip<Ostream,Arg>& manip);
};

template <class Ostream, class Arg>
Ostream&
operator<< (Ostream& ostr, const osmanip<Ostream, Arg>& manip);

template <class charT, class Traits>
inline std::basic_ostream<charT,Traits>&
sfmt(std::basic_ostream<charT,Traits>& ostr, const char* f);

template <class charT, class Traits>
inline osmanip<std::basic_ostream<charT, Traits>, const char*>
setfmt(const char* fmt);

#include "mystream.cpp"

#endif /* __MY_STREAM_H */

// mystream.cpp
#include "mystream.h"

#ifndef __MY_STREAM_CPP
#define __MY_STREAM_CPP

using std::basic_ostream;
using std::use_facet;
using std::ctype;

template <typename charT, typename Traits>
CMyStream<charT, Traits>::CMyStream(basic_ostream<charT, Traits>& ostr,
const char *fmt = "log")
: std:stream(ostr.rdbuf())
{
m_fmt = new charT[strlen(fmt)];
use_facet<ctype<charT> >(ostr.getloc()).widen(fmt, fmt+strlen(fmt),
m_fmt);
}

template <typename charT, typename Traits>
CMyStream<charT, Traits>::~CMyStream()
{
delete[] m_fmt;
}

template <typename charT, typename Traits>
basic_ostream<charT, Traits>&
CMyStream<charT, Traits>::format(const char *fmt)
{
delete[] m_fmt;
m_fmt = new charT[strlen(fmt)];
// use_facet<ctype<charT> >(ostr.getloc()).widen(fmt, fmt+strlen(fmt),
m_fmt); //3
return *this;
}

template <typename charT, typename Traits>
charT *
CMyStream<charT, Traits>::format() const
{
charT *p = new charT[Traits::length(m_fmt)];
Traits::copy(p, m_fmt, Traits::length(m_fmt));
return p;
}

template <typename charT, typename Traits=std::char_traits<charT> >
template<typename T>
CMyStream<charT, Traits>& operator<<(CMyStream<charT, Traits>& ostr, //2
T val)
{
(basic_ostream<charT, Traits>&)ostr << ostr.m_fmt << " ";
(basic_ostream<charT, Traits>&)ostr << val;
}

template <class Ostream, class Arg>
osmanip<Ostream, Arg>:smanip(Ostream& (*pf)(Ostream&, Arg), Arg arg)
: pf_(pf) , arg_(arg)
{
;
}

//4
template <class Ostream, class Arg>
Ostream& operator<< (Ostream& ostr, const osmanip<Ostream, Arg>& manip)
{
(*manip.pf_)(ostr,manip.arg_);
return ostr;
}

template <class charT, class Traits>
inline basic_ostream<charT,Traits>&
sfmt(basic_ostream<charT,Traits>& ostr, const char* f)
{
CMyStream<charT,Traits>* p;
try {
p = dynamic_cast<CMyStream<charT,Traits>*>(&ostr);
}
catch (std::bad_cast) {
return ostr;
}

p->format(f);
return ostr;
}

template <class charT,class Traits>
inline osmanip<basic_ostream<charT, Traits>,const char*>
setfmt(const char* fmt)
{
return osmanip<basic_ostream<charT,Traits>,const char*>(sfmt,fmt);
}

#endif /* __MY_STREAM_CPP */

// mystream_test.cpp
#include "mystream.h"

int
main(int argc, char *argv[])
{
CMyStream<char> strm(std::cout);

strm << "Hello World!" << std::endl;
strm << "123 " << 123 << std::endl;

strm << setfmt<char>("ERROR") << "Byeee" << std::endl;

return 0;
}
 
Reply With Quote
 
 
 
 
kasthurirangan.balaji@gmail.com
Guest
Posts: n/a
 
      06-17-2008
On Jun 17, 4:19*pm, Dan Smithers <(E-Mail Removed)> wrote:
> I want to write my own class derived from the ostream class.
>
> I have been getting errors with my templates:
>
> First, I get an error writing a nested template. If I leave the function
> definition inside template class definition (commented out at //1) then
> it compiles and runs fine, but if I declare and define the function
> separately (at //2).
>
> Is the following syntax supported by g++?
> template<typename charT, typename Traits>
> template<typename T>
> as I get the compiler error
> "mystream.cpp:47: error: too many template-parameter-lists"
>
> I can't get the use_facet command to work (commented out at //3) as I no
> longer have visibility of ostr for getloc and can't call it on my
> derived class. Is there another way of achieving this?
>
> I can't get the manipulator function / object combination to compile.
> "mystream_test.cpp:11: error: no matching function for call to
> ‘setfmt(const char [6])’"
> Do I need to explicitly qualify the template?
>
> Finally, the compiler seems to get confused by the output operator in
> the manipulator (at //4) and issues the following warning:
> "mystream.h:41: warning: friend declaration ‘Ostream&
> operator<<(Ostream&, const osmanip<Ostream, Arg>&)’ declares a
> non-template function
> mystream.h:41: warning: (if this is not what you intended, make sure the
> function template has already been declared and add <> after the
> function name here) -Wno-non-template-friend disables this warning"
>
> Are these problems due to my own misunderstanding of templates?
>
> thanks
>
> dan
>
> I have written my templates in three file (mystream.h, mystream.cpp and
> mystream_test.cpp) and compiling with g++ 4.2.3
>
> // mystream.h
> #include <iostream>
> #ifndef __MY_STREAM_H
> #define __MY_STREAM_H
>
> template <typename charT, typename Traits=std::char_traits<charT> >
> class CMyStream : virtual public std::basic_ostream<charT, Traits>
> {
> public:
> * charT *m_fmt;
>
> public:
> * // constructor
> * CMyStream(std::basic_ostream<charT, Traits>& ostr, const char *fmt);
> * // destructor
> * ~CMyStream();
> * // change format string
> * std::basic_ostream<charT, Traits>& format(const char *fmt);
> * // retrieve format string
> * charT *format() const;
>
> * // output operator
> * template<typename T>
> * friend CMyStream& operator<<(CMyStream& ostr, T val); //1
> // * {
> // * * (std::basic_ostream<charT, Traits>&)ostr << ostr.m_fmt << " ";
> // * * (std::basic_ostream<charT, Traits>&)ostr << val;
> // * }
>
> };
>
> template <class Ostream, class Arg>
> class osmanip {
> public:
> * osmanip(Ostream& (*pf)(Ostream&, Arg), Arg arg);
>
> protected:
> * Ostream& * * (*pf_)(Ostream&, Arg);
> * Arg * * * * *arg_;
>
> * friend Ostream&
> * operator<< (Ostream& ostr, const osmanip<Ostream,Arg>& manip);
>
> };
>
> template <class Ostream, class Arg>
> Ostream&
> operator<< (Ostream& ostr, const osmanip<Ostream, Arg>& manip);
>
> template <class charT, class Traits>
> inline std::basic_ostream<charT,Traits>&
> sfmt(std::basic_ostream<charT,Traits>& ostr, const char* f);
>
> template <class charT, class Traits>
> inline osmanip<std::basic_ostream<charT, Traits>, const char*>
> setfmt(const char* fmt);
>
> #include "mystream.cpp"
>
> #endif /* __MY_STREAM_H */
>
> // mystream.cpp
> #include "mystream.h"
>
> #ifndef __MY_STREAM_CPP
> #define __MY_STREAM_CPP
>
> using std::basic_ostream;
> using std::use_facet;
> using std::ctype;
>
> template <typename charT, typename Traits>
> CMyStream<charT, Traits>::CMyStream(basic_ostream<charT, Traits>& ostr,
> * * * * * * * * * * * * * * * * * * const char *fmt = "log")
> * : std:stream(ostr.rdbuf())
> {
> * m_fmt = new charT[strlen(fmt)];
> * use_facet<ctype<charT> >(ostr.getloc()).widen(fmt, fmt+strlen(fmt),
> m_fmt);
>
> }
>
> template <typename charT, typename Traits>
> CMyStream<charT, Traits>::~CMyStream()
> {
> * delete[] m_fmt;
>
> }
>
> template <typename charT, typename Traits>
> basic_ostream<charT, Traits>&
> CMyStream<charT, Traits>::format(const char *fmt)
> {
> * delete[] m_fmt;
> * m_fmt = new charT[strlen(fmt)];
> // *use_facet<ctype<charT> >(ostr.getloc()).widen(fmt, fmt+strlen(fmt),
> m_fmt); //3
> * return *this;
>
> }
>
> template <typename charT, typename Traits>
> charT *
> CMyStream<charT, Traits>::format() const
> {
> * charT *p = new charT[Traits::length(m_fmt)];
> * Traits::copy(p, m_fmt, Traits::length(m_fmt));
> * return p;
>
> }
>
> template <typename charT, typename Traits=std::char_traits<charT> >
> template<typename T>
> CMyStream<charT, Traits>& operator<<(CMyStream<charT, Traits>& ostr, //2
> * * * * * * * * * * * * * * * * * * *T val)
> {
> * (basic_ostream<charT, Traits>&)ostr << ostr.m_fmt << " ";
> * (basic_ostream<charT, Traits>&)ostr << val;
>
> }
>
> template <class Ostream, class Arg>
> osmanip<Ostream, Arg>:smanip(Ostream& (*pf)(Ostream&, Arg), Arg arg)
> * : pf_(pf) , arg_(arg)
> {
> * ;
>
> }
>
> //4
> template <class Ostream, class Arg>
> Ostream& operator<< (Ostream& ostr, const osmanip<Ostream, Arg>& manip)
> {
> * *(*manip.pf_)(ostr,manip.arg_);
> * *return ostr;
>
> }
>
> template <class charT, class Traits>
> inline basic_ostream<charT,Traits>&
> sfmt(basic_ostream<charT,Traits>& ostr, const char* f)
> {
> * CMyStream<charT,Traits>* p;
> * try {
> * * p = dynamic_cast<CMyStream<charT,Traits>*>(&ostr);
> * }
> * catch (std::bad_cast) {
> * * * return ostr;
> * }
>
> * p->format(f);
> * return ostr;
>
> }
>
> template <class charT,class Traits>
> inline osmanip<basic_ostream<charT, Traits>,const char*>
> setfmt(const char* fmt)
> {
> * return osmanip<basic_ostream<charT,Traits>,const char*>(sfmt,fmt);
>
> }
>
> #endif /* __MY_STREAM_CPP */
>
> // mystream_test.cpp
> #include "mystream.h"
>
> int
> main(int argc, char *argv[])
> {
> * CMyStream<char> strm(std::cout);
>
> * strm << "Hello World!" << std::endl;
> * strm << "123 " << 123 << std::endl;
>
> * strm << setfmt<char>("ERROR") << "Byeee" << std::endl;
>
> * return 0;
>
>
>
> }- Hide quoted text -
>
> - Show quoted text -


Hello,

If i am correct, setfmt template has two template parameters, while
one is alone used when called.
Also, you may want to replace this
template <typename charT, typename Traits=std::char_traits<charT> >

with

template <typename charT, class Traits=std::char_traits<charT> >

I didn't get why would want to write another stream for char when its
already available.

Thanks,
Balaji.
 
Reply With Quote
 
 
 
 
Dan Smithers
Guest
Posts: n/a
 
      06-17-2008
Thanks Balaji,

http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:
> On Jun 17, 4:19 pm, Dan Smithers <(E-Mail Removed)> wrote:
>> I want to write my own class derived from the ostream class.
>>
>> I have been getting errors with my templates:
>>
>> First, I get an error writing a nested template. If I leave the function
>> definition inside template class definition (commented out at //1) then
>> it compiles and runs fine, but if I declare and define the function
>> separately (at //2).
>>
>> Is the following syntax supported by g++?
>> template<typename charT, typename Traits>
>> template<typename T>
>> as I get the compiler error
>> "mystream.cpp:47: error: too many template-parameter-lists"
>>
>> I can't get the use_facet command to work (commented out at //3) as I no
>> longer have visibility of ostr for getloc and can't call it on my
>> derived class. Is there another way of achieving this?
>>
>> I can't get the manipulator function / object combination to compile.
>> "mystream_test.cpp:11: error: no matching function for call to
>> ‘setfmt(const char [6])’"
>> Do I need to explicitly qualify the template?
>>
>> Finally, the compiler seems to get confused by the output operator in
>> the manipulator (at //4) and issues the following warning:
>> "mystream.h:41: warning: friend declaration ‘Ostream&
>> operator<<(Ostream&, const osmanip<Ostream, Arg>&)’ declares a
>> non-template function
>> mystream.h:41: warning: (if this is not what you intended, make sure the
>> function template has already been declared and add <> after the
>> function name here) -Wno-non-template-friend disables this warning"
>>
>> Are these problems due to my own misunderstanding of templates?
>>
>> thanks
>>
>> dan
>>
>> I have written my templates in three file (mystream.h, mystream.cpp and
>> mystream_test.cpp) and compiling with g++ 4.2.3
>>
>> // mystream.h
>> #include <iostream>
>> #ifndef __MY_STREAM_H
>> #define __MY_STREAM_H
>>
>> template <typename charT, typename Traits=std::char_traits<charT> >
>> class CMyStream : virtual public std::basic_ostream<charT, Traits>
>> {
>> public:
>> charT *m_fmt;
>>
>> public:
>> // constructor
>> CMyStream(std::basic_ostream<charT, Traits>& ostr, const char *fmt);
>> // destructor
>> ~CMyStream();
>> // change format string
>> std::basic_ostream<charT, Traits>& format(const char *fmt);
>> // retrieve format string
>> charT *format() const;
>>
>> // output operator
>> template<typename T>
>> friend CMyStream& operator<<(CMyStream& ostr, T val); //1
>> // {
>> // (std::basic_ostream<charT, Traits>&)ostr << ostr.m_fmt << " ";
>> // (std::basic_ostream<charT, Traits>&)ostr << val;
>> // }
>>
>> };
>>
>> template <class Ostream, class Arg>
>> class osmanip {
>> public:
>> osmanip(Ostream& (*pf)(Ostream&, Arg), Arg arg);
>>
>> protected:
>> Ostream& (*pf_)(Ostream&, Arg);
>> Arg arg_;
>>
>> friend Ostream&
>> operator<< (Ostream& ostr, const osmanip<Ostream,Arg>& manip);
>>
>> };
>>
>> template <class Ostream, class Arg>
>> Ostream&
>> operator<< (Ostream& ostr, const osmanip<Ostream, Arg>& manip);
>>
>> template <class charT, class Traits>
>> inline std::basic_ostream<charT,Traits>&
>> sfmt(std::basic_ostream<charT,Traits>& ostr, const char* f);
>>
>> template <class charT, class Traits>
>> inline osmanip<std::basic_ostream<charT, Traits>, const char*>
>> setfmt(const char* fmt);
>>
>> #include "mystream.cpp"
>>
>> #endif /* __MY_STREAM_H */
>>
>> // mystream.cpp
>> #include "mystream.h"
>>
>> #ifndef __MY_STREAM_CPP
>> #define __MY_STREAM_CPP
>>
>> using std::basic_ostream;
>> using std::use_facet;
>> using std::ctype;
>>
>> template <typename charT, typename Traits>
>> CMyStream<charT, Traits>::CMyStream(basic_ostream<charT, Traits>& ostr,
>> const char *fmt = "log")
>> : std:stream(ostr.rdbuf())
>> {
>> m_fmt = new charT[strlen(fmt)];
>> use_facet<ctype<charT> >(ostr.getloc()).widen(fmt, fmt+strlen(fmt),
>> m_fmt);
>>
>> }
>>
>> template <typename charT, typename Traits>
>> CMyStream<charT, Traits>::~CMyStream()
>> {
>> delete[] m_fmt;
>>
>> }
>>
>> template <typename charT, typename Traits>
>> basic_ostream<charT, Traits>&
>> CMyStream<charT, Traits>::format(const char *fmt)
>> {
>> delete[] m_fmt;
>> m_fmt = new charT[strlen(fmt)];
>> // use_facet<ctype<charT> >(ostr.getloc()).widen(fmt, fmt+strlen(fmt),
>> m_fmt); //3
>> return *this;
>>
>> }
>>
>> template <typename charT, typename Traits>
>> charT *
>> CMyStream<charT, Traits>::format() const
>> {
>> charT *p = new charT[Traits::length(m_fmt)];
>> Traits::copy(p, m_fmt, Traits::length(m_fmt));
>> return p;
>>
>> }
>>
>> template <typename charT, typename Traits=std::char_traits<charT> >
>> template<typename T>
>> CMyStream<charT, Traits>& operator<<(CMyStream<charT, Traits>& ostr, //2
>> T val)
>> {
>> (basic_ostream<charT, Traits>&)ostr << ostr.m_fmt << " ";
>> (basic_ostream<charT, Traits>&)ostr << val;
>>
>> }
>>
>> template <class Ostream, class Arg>
>> osmanip<Ostream, Arg>:smanip(Ostream& (*pf)(Ostream&, Arg), Arg arg)
>> : pf_(pf) , arg_(arg)
>> {
>> ;
>>
>> }
>>
>> //4
>> template <class Ostream, class Arg>
>> Ostream& operator<< (Ostream& ostr, const osmanip<Ostream, Arg>& manip)
>> {
>> (*manip.pf_)(ostr,manip.arg_);
>> return ostr;
>>
>> }
>>
>> template <class charT, class Traits>
>> inline basic_ostream<charT,Traits>&
>> sfmt(basic_ostream<charT,Traits>& ostr, const char* f)
>> {
>> CMyStream<charT,Traits>* p;
>> try {
>> p = dynamic_cast<CMyStream<charT,Traits>*>(&ostr);
>> }
>> catch (std::bad_cast) {
>> return ostr;
>> }
>>
>> p->format(f);
>> return ostr;
>>
>> }
>>
>> template <class charT,class Traits>
>> inline osmanip<basic_ostream<charT, Traits>,const char*>
>> setfmt(const char* fmt)
>> {
>> return osmanip<basic_ostream<charT,Traits>,const char*>(sfmt,fmt);
>>
>> }
>>
>> #endif /* __MY_STREAM_CPP */
>>
>> // mystream_test.cpp
>> #include "mystream.h"
>>
>> int
>> main(int argc, char *argv[])
>> {
>> CMyStream<char> strm(std::cout);
>>
>> strm << "Hello World!" << std::endl;
>> strm << "123 " << 123 << std::endl;
>>
>> strm << setfmt<char>("ERROR") << "Byeee" << std::endl;
>>
>> return 0;
>>
>>
>>
>> }- Hide quoted text -
>>
>> - Show quoted text -

>
> Hello,
>
> If i am correct, setfmt template has two template parameters, while
> one is alone used when called.
> Also, you may want to replace this
> template <typename charT, typename Traits=std::char_traits<charT> >
>
> with
>
> template <typename charT, class Traits=std::char_traits<charT> >


I thought that class and typename were synonymous in this context.
>
> I didn't get why would want to write another stream for char when its
> already available.


The reason why I'm doing this is that I have a log class that opens a
file and sends a string together with time information to it. My initial
implementation used a method log(const string& msg) to do this, but that
means that I have to pre-format the string.

ostringstream oss;
oss << "log message" << log_val ...;
my_log(oss.str());

If I make my log class inherit from ostream then I can simply write

my_log << "log_message" << log_val ...;

I thought that while I was doing this I would set up a manipulator so
that I can writethings like
my_log << setformat(Error) << "error message" << err_code;

my_log << setformat(Warning) << "warning message << warning_data;

thanks

dan
 
Reply With Quote
 
Bernd Strieder
Guest
Posts: n/a
 
      06-17-2008
Hello,

Dan Smithers wrote:

> I want to write my own class derived from the ostream class.
>
> I have been getting errors with my templates:
>
> First, I get an error writing a nested template. If I leave the
> function definition inside template class definition (commented out at
> //1) then it compiles and runs fine, but if I declare and define the
> function separately (at //2).


See the corrections below. I've tried to omit the friends where
possible. I have introduce a new public member.

>
> Is the following syntax supported by g++?
> template<typename charT, typename Traits>
> template<typename T>
> as I get the compiler error
> "mystream.cpp:47: error: too many template-parameter-lists"


This happens with template methods of template classes only, you want to
write a free template function, so this should be one list, just
include the typename T in the first list.


>
> I can't get the use_facet command to work (commented out at //3) as I
> no longer have visibility of ostr for getloc and can't call it on my
> derived class. Is there another way of achieving this?


This is due to two-phase lookup. The ostr at that place was not declared
anyway, but just using getloc() within the stream class does not work
either, it has to be this->getloc() to tell the compiler that the
function will be available at instantiation of the template.

>
> I can't get the manipulator function / object combination to compile.
> "mystream_test.cpp:11: error: no matching function for call to
> ?setfmt(const char [6])?"
> Do I need to explicitly qualify the template?


Yes, you have without more changes. The problem is that the template
parameters for the output osmanip instance cannot be derived from input
parameters alone. The input is always const char*. You probably will
have to use a common osmanip for all streams and distinguish the
streams your manipulator can act on dynamically.

>
> Finally, the compiler seems to get confused by the output operator in
> the manipulator (at //4) and issues the following warning:
> "mystream.h:41: warning: friend declaration ?Ostream&
> operator<<(Ostream&, const osmanip<Ostream, Arg>&)? declares a
> non-template function
> mystream.h:41: warning: (if this is not what you intended, make sure
> the function template has already been declared and add <> after the
> function name here) -Wno-non-template-friend disables this warning"
>
> Are these problems due to my own misunderstanding of templates?


Some I think yes. I have some feeling your are following manuals for
some pre-standard compiler or streams library. You can expect that some
things do not work out of the box.

There have been books written just on getting the stuff with streams and
locales right, there are cans full of worms and lots of errors to get
easily caught by. There are existing libraries for logging I would
consider first before rolling my own.

I have put all your code into one file with a few comments and tried to
get it running, see below.

I hope some of the experts on this can help if I have missed something,
especially on getting the manipulator right without the need to
qualify.

HTH,

Bernd Strieder




################################################## ##############


// mystream.h
#include <iostream>
#ifndef __MY_STREAM_H
#define __MY_STREAM_H

template <typename charT, typename Traits=std::char_traits<charT> >
class CMyStream;

template <typename charT, typename Traits >
class CMyStream : virtual public std::basic_ostream<charT, Traits>
{
public:
charT *m_fmt;

public:
// constructor
CMyStream(std::basic_ostream<charT, Traits>& ostr, const char *fmt);
// destructor
~CMyStream();
// change format string
std::basic_ostream<charT, Traits>& format(const char *fmt);
// retrieve format string
charT *format() const;

};

template <class Ostream, class Arg>
class osmanip;


template <class Ostream, class Arg>
Ostream&
operator<< (Ostream& ostr, const osmanip<Ostream, Arg>& manip);

template <class Ostream, class Arg>
class osmanip {
public:
osmanip(Ostream& (*pf)(Ostream&, Arg), Arg arg);

Ostream& manipulate(Ostream&) const;


protected:
Ostream& (*pf_)(Ostream&, Arg);
Arg arg_;

};


template <class charT, class Traits>
inline std::basic_ostream<charT,Traits>&
sfmt(std::basic_ostream<charT,Traits>& ostr, const char* f);

template <class charT, class Traits>
inline osmanip<std::basic_ostream<charT, Traits>, const char*>
setfmt(const char* fmt);

//#include "mystream.cpp"`

#endif /* __MY_STREAM_H */

// mystream.cpp
//#include "mystream.h"

#ifndef __MY_STREAM_CPP
#define __MY_STREAM_CPP

using std::basic_ostream;
using std::use_facet;
using std::ctype;

template <typename charT, typename Traits>
CMyStream<charT, Traits>::CMyStream(basic_ostream<charT, Traits>& ostr,
const char *fmt = "log")
: std:stream(ostr.rdbuf())
{
m_fmt = new charT[strlen(fmt)];
use_facet<ctype<charT> >(ostr.getloc()).widen(fmt, fmt+strlen(fmt),
m_fmt);
}

template <typename charT, typename Traits>
CMyStream<charT, Traits>::~CMyStream()
{
delete[] m_fmt;
}

template <typename charT, typename Traits>
basic_ostream<charT, Traits>&
CMyStream<charT, Traits>::format(const char *fmt)
{
delete[] m_fmt;
m_fmt = new charT[strlen(fmt)];
use_facet<ctype<charT> >(this->getloc()).widen(fmt, fmt+strlen(fmt),
m_fmt); //3
return *this;
}

template <typename charT, typename Traits>
charT *
CMyStream<charT, Traits>::format() const
{
charT *p = new charT[Traits::length(m_fmt)];
Traits::copy(p, m_fmt, Traits::length(m_fmt));
return p;
}

template <typename T, typename charT, typename Traits>
CMyStream<charT, Traits>& operator<<(CMyStream<charT, Traits>& ostr, //2
T val)
{
(basic_ostream<charT, Traits>&)ostr << ostr.m_fmt << " ";
(basic_ostream<charT, Traits>&)ostr << val;
return ostr;
}

template <class Ostream, class Arg>
osmanip<Ostream, Arg>:smanip(Ostream& (*pf)(Ostream&, Arg), Arg arg)
: pf_(pf) , arg_(arg)
{
;
}

template <class Ostream, class Arg>
Ostream&
osmanip<Ostream, Arg>::manipulate(Ostream& ostr) const
{
return (*pf_)(ostr,arg_);
}

//4
template <class Ostream, class Arg>
Ostream& operator<< (Ostream& ostr, const osmanip<Ostream, Arg>& manip)
{
// (*manip.pf_)(ostr,manip.arg_);
// return ostr;
return manip.manipulate(ostr);
}

template <class charT, class Traits>
inline basic_ostream<charT,Traits>&
sfmt(basic_ostream<charT,Traits>& ostr, const char* f)
{
CMyStream<charT,Traits>* p;
try {
p = dynamic_cast<CMyStream<charT,Traits>*>(&ostr);
}
catch (std::bad_cast) {
return ostr;
}

p->format(f);
return ostr;
}

template <class charT,class Traits>
inline osmanip<basic_ostream<charT, Traits>,const char*>
setfmt(const char* fmt)
{
return osmanip<basic_ostream<charT,Traits>,const char*>(sfmt,fmt);
}

#endif /* __MY_STREAM_CPP */

// mystream_test.cpp
//#include "mystream.h"

int
main(int argc, char *argv[])
{
CMyStream<char> strm(std::cout);

strm << "Hello World!" << std::endl;
strm << "123 " << 123 << std::endl;

strm << setfmt<char, std::char_traits<char> >("ERROR") << "Byeee" <<
std::endl;

return 0;
}

 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      06-18-2008
On Jun 17, 3:22 pm, Dan Smithers <(E-Mail Removed)> wrote:
> (E-Mail Removed) wrote:


[...]
> > Also, you may want to replace this
> > template <typename charT, typename Traits=std::char_traits<charT> >


> > with


> > template <typename charT, class Traits=std::char_traits<charT> >


> I thought that class and typename were synonymous in this context.


They are. A lot of experts (but not all) prefer using typename
systematically in this case, to avoid confusion.

> > I didn't get why would want to write another stream for char
> > when its already available.


> The reason why I'm doing this is that I have a log class that
> opens a file and sends a string together with time information
> to it.


That's easily done using a forwarding streambuf, see
http://kanze.james.neuf.fr/articles/fltrsbf1.html. More
generally, it is often desirable to make logging configurable,
etc., which often leads to a wrapper (not derivation) around
ostream; there's a generic implementation of this in the code at
my site (along with full implementations of output and input
filtering streambuf): go to the code section, then look up
OutputStreamWrapper in the IO subsection.

> My initial implementation used a method log(const
> string& msg) to do this, but that means that I have to
> pre-format the string.


> ostringstream oss;
> oss << "log message" << log_val ...;
> my_log(oss.str());


> If I make my log class inherit from ostream then I can simply write


> my_log << "log_message" << log_val ...;


You can do that with a wrapper as well. And if all you need is
the time stamp, a filtering streambuf means that you're using an
istream; you don't need to inherit (or if you do, it's only to
provide convenience constructors).

> I thought that while I was doing this I would set up a
> manipulator so that I can writethings like
> my_log << setformat(Error) << "error message" << err_code;


> my_log << setformat(Warning) << "warning message << warning_data;


This is most often handled by something like:

log( Log::error ) << "message" ... ;
log( Log::warning ) << "message" ... ;

The function "log" determines whether logging at this level is
active or not, and returns a corresponding OutputStreamWrapper.

Note that the destructor of the OutputStreamWrapper here can be
used to force a flush (and ensure that every log message ends
with a new line, if it collaborates with the filtering
streambuf), and the class itself can also grab a lock in its
constructor, and release it in the destructor, to ensure
synchronization in a multi-threaded environment.

--
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
 
Dan Smithers
Guest
Posts: n/a
 
      06-18-2008
Thank you very much Bernd,

I thought that I had tried using this->getloc() during my trials. I
guess that either I had dismissed it as being implicit, or tried it at
the same time as some other "fix" and taken them all out when it didn't
all work.

I see that I had made m_fmt public. If I wanted it private, then
operator<< would need to be a friend, or use an access method. Which is
better?

Can you suggest where I should look for good log libraries?

thanks again

dan
 
Reply With Quote
 
Bernd Strieder
Guest
Posts: n/a
 
      06-18-2008
Hello,

Dan Smithers wrote:

> Thank you very much Bernd,


You're welcome.

>
> I thought that I had tried using this->getloc() during my trials. I
> guess that either I had dismissed it as being implicit, or tried it at
> the same time as some other "fix" and taken them all out when it
> didn't all work.


It is pretty hard to learn that template stuff just by trying and
without working through some textbook. Even worse, you might be faced
with code from different times, when even the textbooks told different
things, or when textbooks on some matter did not exist.

I think what you have tried about iostreams has been tried often enough
and you can find a lot to read about it, but sometimes that stuff does
not hold anymore to the word.

>
> I see that I had made m_fmt public. If I wanted it private, then
> operator<< would need to be a friend, or use an access method. Which
> is better?


IMO it is better to provide some public methods doing just the work you
need on those data members. Then you can avoid most of that friend
business. Those extra public methods could do fine-grained checks, so
it could be public without posing threats.

>
> Can you suggest where I should look for good log libraries?


Use keywords "C++ logging library" at a search engine, there are loads
of such libraries. What is good depends on your actual requirements.
Maybe you can find some projects similar to yours and see how they do.

With the danger to become OT here, some thoughts on logging:

If logging is an inherent part of your project, then why not designing
it in an application specific manner, i.e. you design a logging
interface not as generic as the iostreams library, but to your needs.
If you have something to log, then the actual formatting of the message
is arbitrary at that place, while using that operator<< interface to
iostreams concerns you with the actual formatting all over. The best
you can get is a method taking the context info through parameters
creating the log message and routing it to the right place.

And sometimes logging has to be done different depending on the platform
and the language. If you do logging through an application specific
interface, then porting and translating the logging requires work only
behind that interface.

Bernd

 
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
deriving a class from a base class markww C++ 1 08-22-2006 11:55 AM
Deriving input stream ? fabricemarchant@free.fr C++ 4 05-27-2006 08:38 PM
Problem deriving from WebControl Class Gary Rynearson ASP .Net 0 11-18-2005 03:34 PM
Deriving abstract class from non-abstract class Matthias Kaeppler Java 1 05-22-2005 01:28 PM
Problem in deriving custome class from XmlNode Mahesh Devjibhai Dhola ASP .Net 0 10-15-2004 07:38 AM



Advertisments