Logging class and overloaded stream operators [question #2]

Discussion in 'C++' started by Riku Jarvinen, Oct 25, 2005.

  1. Hi everyone,

    I asked another question regarding this same subject about a week ago. See
    thread:

    http://groups.google.fi/group/comp....579d6832732/530bae667a479add#530bae667a479add

    So, the basic idea is to have a compact logger class which can be used like
    the std::cout stream and add extra functionality to it (line numbering, some
    output counters etc.).

    The class should also accept the iostream manipulators, including special
    manipulators in <iomanip>. How can I make the logging class handle all the
    manipulators in the same way std::cout does?

    If I compile the code (see below) which tries to use the manipulators with
    the Logger class, I get the following error messages:

    > g++ example2.cpp


    example2.cpp: In function `int main()':
    example2.cpp:51: error: no match for 'operator<<' in 'mainlog <<
    std::setw(int)()'
    example2.cpp:22: error: candidates are: Logger& Logger::eek:perator<<(const
    char*)
    example2.cpp:28: error: Logger& Logger::eek:perator<<(double)
    example2.cpp:52: error: no match for 'operator<<' in '
    (+(&mainlog)->Logger::eek:perator<<(" x = "))->Logger::eek:perator<<(x) <<
    std::endl'
    example2.cpp:22: error: candidates are: Logger& Logger::eek:perator<<(const
    char*)
    example2.cpp:28: error: Logger& Logger::eek:perator<<(double)
    example2.cpp:53: error: `precision' undeclared (first use this function)
    example2.cpp:53: error: (Each undeclared identifier is reported only once
    for
    each function it appears in.)
    example2.cpp:54: error: no match for 'operator<<' in '
    (&mainlog)->Logger::eek:perator<<("x = ") << std::showpos'
    example2.cpp:22: error: candidates are: Logger& Logger::eek:perator<<(const
    char*)
    example2.cpp:28: error: Logger& Logger::eek:perator<<(double)


    Simplified example code:

    ------------------------------------
    #include <iostream>
    #include <fstream>
    #include <iomanip>

    using namespace std;

    class Logger
    {
    public:
    Logger(const char* filename = "program.log")
    {
    logfile = new fstream(filename, fstream::eek:ut);
    }

    ~Logger()
    {
    logfile->close();
    delete logfile;
    }

    Logger& operator<<(const char* msg)
    {
    *logfile << msg;
    return *this;
    }

    Logger& operator<<(const double val)
    {
    *logfile << val;
    return *this;
    }

    private:
    fstream* logfile;
    };

    int main()
    {
    Logger mainlog;
    double x = 12.34567;

    // These work fine
    cout << setw(20) << setfill('*') << setprecision(4);
    cout << " x = " << x << endl;
    cout.precision(2);
    cout << "x = " << showpos << scientific << x << endl;

    mainlog << "x = " << x << "\n";

    // These don't work
    //mainlog << setw(20) << setfill('*') << setprecision(4);
    //mainlog << " x = " << x << endl;
    //mainlog.precision(2);
    //mainlog << "x = " << showpos << scientific << x << endl;

    return 0;
    }
    ------------------------------------

    Any comments/suggestions are again very welcome!

    Riku

    --
    life, space, irc
     
    Riku Jarvinen, Oct 25, 2005
    #1
    1. Advertising

  2. Riku Jarvinen

    Kai-Uwe Bux Guest

    Riku Jarvinen wrote:

    > Hi everyone,
    >
    > I asked another question regarding this same subject about a week ago. See
    > thread:
    >
    >

    http://groups.google.fi/group/comp....579d6832732/530bae667a479add#530bae667a479add
    >
    > So, the basic idea is to have a compact logger class which can be used
    > like the std::cout stream and add extra functionality to it (line
    > numbering, some output counters etc.).
    >
    > The class should also accept the iostream manipulators, including special
    > manipulators in <iomanip>. How can I make the logging class handle all the
    > manipulators in the same way std::cout does?
    >
    > If I compile the code (see below) which tries to use the manipulators with

    [snip]
    >
    >
    > Simplified example code:
    >
    > ------------------------------------
    > #include <iostream>
    > #include <fstream>
    > #include <iomanip>
    >
    > using namespace std;
    >
    > class Logger
    > {
    > public:
    > Logger(const char* filename = "program.log")
    > {
    > logfile = new fstream(filename, fstream::eek:ut);
    > }
    >
    > ~Logger()
    > {
    > logfile->close();
    > delete logfile;
    > }
    >
    > Logger& operator<<(const char* msg)
    > {
    > *logfile << msg;
    > return *this;
    > }
    >
    > Logger& operator<<(const double val)
    > {
    > *logfile << val;
    > return *this;
    > }


    what about replacing all these by a template:

    template < typename T >
    Logger& operator<< ( T const & t ) {
    *logfile << val;
    return *this;
    }

    This should handle the manipulators, too. (not tested!)

    >
    > private:
    > fstream* logfile;
    > };
    >
    > int main()
    > {
    > Logger mainlog;
    > double x = 12.34567;
    >
    > // These work fine
    > cout << setw(20) << setfill('*') << setprecision(4);
    > cout << " x = " << x << endl;
    > cout.precision(2);
    > cout << "x = " << showpos << scientific << x << endl;
    >
    > mainlog << "x = " << x << "\n";
    >
    > // These don't work
    > //mainlog << setw(20) << setfill('*') << setprecision(4);
    > //mainlog << " x = " << x << endl;
    > //mainlog.precision(2);
    > //mainlog << "x = " << showpos << scientific << x << endl;
    >
    > return 0;
    > }



    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Oct 25, 2005
    #2
    1. Advertising

  3. Kai-Uwe Bux wrote:
    >


    Code:
    [color=blue]
    >
    > what about replacing all these by a template:
    >
    >     template < typename T >
    >     Logger& operator<< ( T const & t ) {
    >       *logfile << val;
    >       return *this;
    >     }
    >
    > This should handle the manipulators, too. (not tested!)
    >[/color]
    
    I tried this typename template and it didn't seem to help in the manipulator 
    issue. I think I can add something like:
    
    Logger& Logger::operator<<(ios_base& (*pf)(ios_base&))
    {
       *logfile << pf;
       return *this;
    }
    
    but this works only with the manipulators in ios_base and, for example, 
    precision is a member function of ios_base, not a manipulator. Any thoughts?
    
    Riku
    [color=blue]
    >
    >
    > Best
    >
    > Kai-Uwe Bux [/color]
     
    Riku Jarvinen, Oct 26, 2005
    #3
  4. Riku Jarvinen

    Kai-Uwe Bux Guest

    Riku Jarvinen wrote:

    > Kai-Uwe Bux wrote:
    >>

    >
    >
    Code:
    > [color=green]
    >>
    >> what about replacing all these by a template:
    >>
    >>     template < typename T >
    >>     Logger& operator<< ( T const & t ) {
    >>       *logfile << val;
    >>       return *this;
    >>     }
    >>
    >> This should handle the manipulators, too. (not tested!)
    >>[/color]
    > 
    > I tried this typename template and it didn't seem to help in the
    > manipulator issue. I think I can add something like:[/color]
    
    The only issue I see is the use of std::endl. Have a look at:
    
    
    #include <iostream>
    #include <fstream>
    #include <iomanip>
    
    using namespace std;
    
    class Logger
    {
     public:
      Logger(const char* filename = "program.log")
      {
        logfile = new fstream(filename, fstream::out);
      }
      
      ~Logger()
      {
        logfile->close();
        delete logfile;
      }
    
      template < typename T >
      Logger& operator<<( T const & t ) 
      {
        *logfile << t;
        return *this;
      }
    
      void precision ( unsigned long p ) {
        *logfile << std::setprecision( p );
      }
      
     private:
      fstream* logfile;
    };
    
    int main()
    {
      Logger mainlog;
      double x = 12.34567;
      
      // These work fine
      cout << setw(20) << setfill('*') << setprecision(4);
      cout << " x = " << x << endl;
      cout.precision(2);
      cout << "x = " << showpos << scientific << x << endl;
      
      mainlog << "x = " << x << "\n";
      mainlog << setw(20) << setfill('*') << setprecision(4);
      mainlog << " x = " << x << '\n';
      mainlog.precision(2);
      mainlog << "x = " << showpos << scientific;
      mainlog << x << '\n';
      
      return 0;
    }
    
    [color=blue]
    > Logger& Logger::operator<<(ios_base& (*pf)(ios_base&))
    > {
    >    *logfile << pf;
    >    return *this;
    > }
    > 
    > but this works only with the manipulators in ios_base and, for example,
    > precision is a member function of ios_base, not a manipulator. Any
    > thoughts?[/color]
    
    See above. However, I do not yet have an idea about how to deal with endl.
    
    
    
    Best
    
    Kai-Uwe Bux
     
    Kai-Uwe Bux, Oct 26, 2005
    #4
  5. Kai-Uwe Bux wrote:
    > Riku Jarvinen wrote:
    >>
    >> I tried this typename template and it didn't seem to help in the
    >> manipulator issue. I think I can add something like:

    >
    > The only issue I see is the use of std::endl. Have a look at:


    Ok, thanks!

    I think I have to include separately every member function of std::eek:stream,
    std::ios and std::ios_base in the Logger class if I want to make it exactly
    like std::cout?

    >
    > However, I do not yet have an idea about how to deal with endl.
    >


    Actually, this (and all the other basic operator<< manipulators) can be
    handled with the following addition to the class:

    Logger& Logger::eek:perator<<(ostream& (*pf)(ostream&))
    {
    *logfile << pf;
    return *this;
    }


    Riku

    >
    >
    > #include <iostream>
    > #include <fstream>
    > #include <iomanip>
    >
    > using namespace std;
    >
    > class Logger
    > {
    > public:
    > Logger(const char* filename = "program.log")
    > {
    > logfile = new fstream(filename, fstream::eek:ut);
    > }
    >
    > ~Logger()
    > {
    > logfile->close();
    > delete logfile;
    > }
    >
    > template < typename T >
    > Logger& operator<<( T const & t )
    > {
    > *logfile << t;
    > return *this;
    > }
    >
    > void precision ( unsigned long p ) {
    > *logfile << std::setprecision( p );
    > }
    >
    > private:
    > fstream* logfile;
    > };
    >
    > int main()
    > {
    > Logger mainlog;
    > double x = 12.34567;
    >
    > // These work fine
    > cout << setw(20) << setfill('*') << setprecision(4);
    > cout << " x = " << x << endl;
    > cout.precision(2);
    > cout << "x = " << showpos << scientific << x << endl;
    >
    > mainlog << "x = " << x << "\n";
    > mainlog << setw(20) << setfill('*') << setprecision(4);
    > mainlog << " x = " << x << '\n';
    > mainlog.precision(2);
    > mainlog << "x = " << showpos << scientific;
    > mainlog << x << '\n';
    >
    > return 0;
    > }
    >
    >
    >> Logger& Logger::eek:perator<<(ios_base& (*pf)(ios_base&))
    >> {
    >> *logfile << pf;
    >> return *this;
    >> }
    >>
    >> but this works only with the manipulators in ios_base and, for example,
    >> precision is a member function of ios_base, not a manipulator. Any
    >> thoughts?

    >
    > See above. However, I do not yet have an idea about how to deal with endl.
    >
    >
    >
    > Best
    >
    > Kai-Uwe Bux
     
    Riku Jarvinen, Oct 26, 2005
    #5
  6. Hi!

    Riku Jarvinen schrieb:
    > [...]
    >
    > So, the basic idea is to have a compact logger class which can be used
    > like the std::cout stream and add extra functionality to it (line
    > numbering, some output counters etc.).
    > [...]
    >
    > Any comments/suggestions are again very welcome!


    You could implement a streambuf derived class and and build an ostream
    class with it. This ostream then can be used like any other ostream (I
    implemented a iostream wrapper for bzip2 library this way).

    Thomas
     
    Thomas J. Gritzan, Oct 26, 2005
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    1
    Views:
    548
    Victor Bazarov
    Feb 7, 2005
  2. Replies:
    4
    Views:
    507
  3. Riku Jarvinen
    Replies:
    7
    Views:
    526
    Riku Jarvinen
    Oct 24, 2005
  4. Replies:
    13
    Views:
    531
    James Kanze
    May 27, 2006
  5. iluvatar
    Replies:
    3
    Views:
    341
    Sylvester Hesp
    Feb 12, 2007
Loading...

Share This Page