0

When I try my own version I am getting

error C2039: 'endl' : is not a member of 'abc' error C2065: 'endl' : undeclared identifier

Here is the code below.

#include <iostream>
#include <stdio.h>

//assume this class uses some proprietary logging system.  I just use the wrap the C
//output functions here but assume is a corporate log system
namespace abc {

   class log_stream
   {
   public:
      log_stream(const char* filename) {
         fp_ = fopen(filename, "w");
      }

      log_stream& operator<<(short val)          { if (fp_) { output_int(val); } return *this; }
      log_stream& operator<<(unsigned short val) { if (fp_) { output_int(val); } return *this; }
      log_stream& operator<<(int val)            { if (fp_) { output_int(val); } return *this; }
      log_stream& operator<<(unsigned int val)   { if (fp_) { output_int(val); } return *this; }
      log_stream& operator<<(long val)           { if (fp_) { output_int(val); } return *this; }
      log_stream& operator<<(unsigned long val)  { if (fp_) { output_int(val); } return *this; }
      log_stream& operator<<(const char* val)    { if (fp_) { output_string(val); } return *this; }
      inline log_stream& endl(log_stream& os)  { return os.endl(); }
      //etc
      log_stream& endl() {
         if(fp_)
            fputc('\n', fp_);
         return *this;
      }

   private:
      void output_int(long v) { fprintf(fp_, "%d", v); }
      void output_string(const char* s) { fprintf(fp_, "%s", s); }
      FILE* fp_;
   };
}  //namespace abc

int main() {
   abc::log_stream logger("myfile.txt");
   //error C2039: 'endl' : is not a member of 'abc', error C2065: 'endl' : undeclared identifier
   logger << "number " << 3 << abc::endl;
   return 0;
}

UPDATE:

If I add

inline log_stream& endl(log_stream& os)  { return os.endl(); }

inside the abc namespace (but outside the class, I then get

error C2678: binary '<<' : no operator found which takes a left-hand operand of type 'abc::log_stream' (or there is no acceptable conversion)

Which is closer (I think) to solving, but not there yet.

UPDATE2.

Well, that was hairy! Here is how I fixed problem for anyone doing anything similar. Thanks Julien.

added these to class:

  ~log_stream() { if(fp_) fclose(fp_); }

  // this is the main one I was missing
  abc::log_stream& abc::log_stream::operator<<( log_stream& (*pf)(log_stream&) )
  {
     return pf(*this);
  }

Then outside class:

abc::log_stream& endl( abc::log_stream& log ) { log.endl(); return log; }

Angus Comber
  • 9,316
  • 14
  • 59
  • 107
  • I see an `endl` member function in the `log_stream` class. I see no `endl` entity declared top level in the `abc` namespace. Am I missing something? – Benjamin Lindley Sep 27 '13 at 14:49
  • Somewhat off-topic - do you really want a logging stream with its own implementation? Have a look at http://marcoarena.wordpress.com/2013/09/13/dont-couple-streams-with-devices/ –  Sep 27 '13 at 14:58
  • After your update: Now see John's answer. – Benjamin Lindley Sep 27 '13 at 14:59

2 Answers2

1

std::endl is a function taking a std::ostream as its single parameter, and ostream<< is an overload which takes the type of std::endl.

To copy this behavior for your log_stream, override std::endl for it:

abc::log_stream& std::endl( abc::log_stream& log )
{
    log.endl();
    return log;
}

and override abc::log_stream::operator<< to use it:

abc::log_stream& abc::log_stream::operator<<( log_stream& (*pf)(log_stream&) )
{
    return pf(*this);
}

As you can see, the argument of abc::log_stream::operator<< takes the type of std::endl as argument.

Also, note that std::endl flushes the stream. Thus you should consider calling fflush(fp_) in abc::log::endl().

Julien
  • 2,139
  • 1
  • 19
  • 32
  • Brilliant, thanks. I did start on road to implementing the operator<<(function ptr bit - but was struggling. Yes I realised about flush - is on todo list. – Angus Comber Sep 27 '13 at 15:47
0

I think you should make an operator<< that takes your endl type. Or let it take std::endl. See also this answer to a similar question: https://stackoverflow.com/a/1134467/4323 - basically, endl is a function like you have, but you need to make an insertion operator for your class that accepts that function as its right-hand argument, and invokes it.

Community
  • 1
  • 1
John Zwinck
  • 239,568
  • 38
  • 324
  • 436