Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations derfloh on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How do I use the operator<< ??

Status
Not open for further replies.

cpjust

Programmer
Joined
Sep 23, 2003
Messages
2,132
Location
US
I'm not sure if this is even possible. All of the operator<< examples I've seen so far just allow cout to recognize new classes...

What I am trying to do is basically write my own sort of cout object to print to screen, files... or specially format the data. But I want to still be able to use cout the way it normally works. Here is an example of what I would like to do:

...
cout << &quot;Print normal text.&quot; << endl;
myCout << &quot;Only print this if a debug flag is set.&quot; << endl;
...

I know that I could wrap all my conditional cout's in an #ifdef DEBUG block, but I'd like it to look cleaner like above.

This is what I thought I could do, but I'm getting a lot of compile errors with it...

class myCout
{
public:
ostream& operator<<( ostream& out, myCout& me );
};

If anyone has any suggestions, I'd really appreciate them.
Thanks,
Chris.
 
You're quite close, only the << operator isn't really part of the class, its works best as a stand alone function (otherwise, depending on situation, the compiler might not realize that the operator is applicable).

For instance, say YourClass looks like this:
Code:
class YourClass
{
public:
  YourClass(const char* name):mName(name){};
  const char* getName() const { return mName; }
private:
  const char* mName;
};

You could then define an operator like
Code:
ostream& operator<<( ostream& out, const YourClass& theClass )
{
  out << &quot;YourClass.Name=&quot; << theClass.getName();
  return out;
}

And at some other point use it:
Code:
  YourClass foo(&quot;SomeName&quot;);
  cout << foo;

Sometimes you see stuff like
Code:
friend ostream& operator<<(ostream& , const TheClass& );
inside class definitions, but thats just to allow the << operator to access the class' private members.


/Per

if (typos) cout << &quot;My fingers are faster than my brain. Sorry for the typos.&quot;;
 
Here's a quick 'n' dirty example of something that might work. I didn't test it, and I'm unsure of my friend syntax with templates, so you might have to play around with that a bit:

Code:
class DebugOutputStream
{
      template< typename T >
    friend DebugOutputStream& operator<<( DebugOutputStream&, const T& );

  public:
    DebugOutputStream( ostream& s )
    : stream( s )
    {}

  private:
    ostream& stream;
};

  template< typename T >
DebugOutputStream& operator<<( DebugOutputStream& out, const T& t )
{
#ifndef NODEBUG
    out.stream << t;
#endif

    return out;
}


The usage would be as follows:

Code:
DebugOutputStream dcout( cout );  // make a debug stream
                                  // that's connected to cout
cout << &quot;Always print me.\n&quot;;
dcout << &quot;Print me in debug.\n&quot;;
 
Oh, and I meant &quot;NDEBUG,&quot; not &quot;NODEBUG&quot;... but you probably knew that.
 
Thanks, I tried that and was able to get it down to 1 compile error. I'm not sure where to go from here.
Here's what I have:

#include <strstrea.h>

class COut
{
template<class T>
friend COut& operator<<( COut& out, T& t );

public:
COut();
virtual ~COut();
COut( ostream& s ) : stream( s ) {}

private:
COut& operator=( COut& ); // Not Permitted.
ostream& stream;
};

template<class T>
COut& operator<<( COut& out, T& t )
{
out.stream << endl << &quot;*** Debug ***&quot; << endl << t << endl << &quot;*** End Debug ***&quot; << endl;
return out;
}

void main(void)
{
COut debug(cout);
debug << endl << &quot;This is a test.&quot; << endl;
}

I'm getting the following compile error on the 2nd line in main():
&quot;error C2679: binary '<<' : no operator defined which takes a right-hand operand of type 'const char *' (or there is no acceptable conversion)&quot;
 
This is the problem (except the unimplemented destructor :-) )

Code:
template <class T> 
COut& operator<<( COut& out, T& t )
{
   out.stream << endl << &quot;*** Debug ***&quot; << endl << t << endl << &quot;*** End Debug ***&quot; << endl;
   return out;
}

because if you do a
debug << &quot;foo&quot; << endl;

First you'd have a << &quot;ww&quot; that returns a template <char*> reference thinge, but the input for this is the endl, and that's a different type and the compliler cant match the 2.

debug << &quot;foo&quot; << &quot;bar&quot;
should work though since they are of the same type.



/Per

if (typos) cout << &quot;My fingers are faster than my brain. Sorry for the typos.&quot;;
 
This operator<<() is really confusing me... I wish the MSDN documented it better.
I tried adding this, but obviously it didn't help:

COut& operator<<( COut& out, const char* psz )
{
out.stream << &quot;\n*** Debug ***\n&quot; << psz << &quot;\n*** End Debug ***\n&quot;;
return out;
}

Can you explain what the two parameters and return value are used for? I'm guessing the second parameter is the string (or other type) on the right side of the <<, but I'm not sure where the COut& parameter and return types are if you use something like this:

COut << &quot;Hello&quot; << &quot;World&quot;;

The second << would seem to be passing the string &quot;World&quot; to the string &quot;Hello&quot;. But obviously a const char* wouldn't know what to do with another const char*.

Also, the original operator<<() function was using a template as the second parameter, but in the main() function we don't specify what T& should be. I'm also a bit new to templates, but I would have thought that I would need to create the object like this:

COut<const char*> debug(cout);

Thanks for the help,
Chris.
 
COut& operator<<( COut& out, const char* psz )

The input:
out: is what's on the left side of the <<
psz: is what's on the right side, just as you said.

The return value:
The possibility to do multiple stuff like
Code:
cout << &quot;Foo&quot; << &quot;Bar&quot;;
is because the operator returns a COut&, that COut& is the inparameter to the next <<.

Perhaps it looks a bit clearer if we instead of operator << use a method, lets call it print:
Code:
COut& COut::print(const char* psz )
{
  ...
}

cout.print(&quot;foo&quot;).bar(&quot;bar&quot;)

The principle is basically the same, although the syntax when using << operator is slightly different.

About the templates:
Yes you're right, something like that gets generated. The problem with the template solution is that the compiler don't know how to match the
COut<const char*> and the COut<theTypeOfendl> and use the one as an input to the other.






/Per

if (typos) cout << &quot;My fingers are faster than my brain. Sorry for the typos.&quot;;
 
typos = true;

>cout.print(&quot;foo&quot;).bar(&quot;bar&quot;)

should of course be
cout.print(&quot;foo&quot;).print(&quot;bar&quot;)

/Per

if (typos) cout << &quot;My fingers are faster than my brain. Sorry for the typos.&quot;;
 
Hmm... Let me redefine the function like this for clarity:
COut& operator<<( COut& left, const char* right )

If I do this:
debug << &quot;First&quot; << &quot;Second&quot;;

then parameter 'right' would be &quot;Second&quot; and parameter 'left' would be &quot;First&quot; which are both const char*.
Then for the first <<, the 'right' parameter would be the COut& return value of the other <<, and both the 'left' parameter and the return value would be debug which is a COut object. Is that right?

With the above assumption, I tried adding this:

COut& operator<<( const char* left, const char* right )
{
COut out(cout);
out.stream << left << right;
return out;
}

But now I'm getting this compile error on my new operator<<():
&quot;error C2803: 'operator <<' must have at least one formal parameter of class type&quot;

So I'm guessing one of the parameters has to be a COut type, but since the left and right sides of << are const char* that wouldn't make sense...?
 
Code:
COut& operator<<( COut& left, const char* right )
cout << &quot;First&quot; << &quot;Second&quot;;

Ok, lets take it one << at the time.

1) The first << operation is this:
cout << &quot;First&quot; :
left = cout
right = &quot;First&quot;

2) The second operation is this:
(result of above) << &quot;Second&quot;
left = the returned Cout& from cout << &quot;First&quot;
right = &quot;Second&quot;

>the left and right sides of << are const char* that wouldn't make sense...?

Its not a
Code:
cout (&quot;First&quot; << &quot;Second&quot;)
thingie, but rather a
Code:
(cout << &quot;First&quot;) << &quot;Second&quot;

Or with a lot:
Code:
cout << &quot;1st&quot; << &quot;2nd&quot; << &quot;3rd&quot; << &quot;4th&quot;
=>
(((cout << &quot;1st&quot;) << &quot;2nd&quot;) << &quot;3rd&quot;) << &quot;4th&quot;

Notice how the value to the left is always a COut&
Makes more sense now?




/Per

if (typos) cout << &quot;My fingers are faster than my brain. Sorry for the typos.&quot;;
 
Thanks, that makes sense.
I thought C/C++ statements always got executed from right to left...
With this in mind, I'll try fiddling with these functions some more to see if I can get it to work.

BTW, do you know what type 'endl' actually is?
 
Simple answer: It's a manipulator object. Don't worry about it too much.


Better answer: endl is really a function. operator<< is overloaded to take certain types of functions and, instead of &quot;outputting&quot; them, call them with the stream as an argument.

Effectively:

Code:
cout << endl;

is the same as

Code:
endl( cout );
 
At least that's how it's normally implemented. I'm not sure if the Standard explicitly says it has to be done that way or just gives it as an example.
 
PerFnurt, the class itself isn't templated, it's the member function. So:

Code:
debug << &quot;foo&quot;

returns a COut&, not a COut<const char*>& or anything like that. So that shouldn't be affecting the call, as far as I can tell. All operator calls have the same left hand type.

Unfortunately, I just tested the thing today (on gcc) and it works fine with everything (cascading between different types) until it hits an endl, saying it's of an unknown type. In other words, apparently a different problem than cpjust...

That template member function should be picking up the type of the function, as far as I can tell. It seems like a compiler error rather than a programmer error, but I'm not sure... any template metaprogrammers in the house?
 
chipperMDW: Yeah you're right. I got confused when I tested it.


/Per

if (typos) cout << &quot;My fingers are faster than my brain. Sorry for the typos.&quot;;
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top