views:

854

answers:

4

any system defined user type past to ostream object is converted to a string or char* ?

like cout<<4<<"Hello World";

works perfectly fine, how is this achieved? is the << operator overloaded for each and every type? is there a way to achieve it through just one generic overloaded function? what i mean is can i have just one overloaded operator method with one parameter(like void*) and then decide inside that method how to typecast integer to char*

Things worked partially if i overload operator << using Template i.e

class UIStream
{
private:
 ofstream stream;
public:
 UIStream();
 ~UIStream();
 template <typename T>
 UIStream& operator << (const T);
};

so this works

 UIStream my_stream;
 my_stream<<"bcd"<10;

however it gives compiler error when i do this

my_stream <<endl;

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

Is not std::endl a type of object too?

+1  A: 

is the << operator overloaded for each and every type?

yes

is there a way to achieve it through just one generic overloaded function?

this question doesn't make sense .. do you want just one function, or do you want an overloaded function?

eduffy
my second question meant can i have just one overloaded function that could take just one parameter (something like void*) and than i can typecast everything thats passed to the overloaded operator inside the function
Kazoom
Do you mean a template function?
eduffy
i m trying to overlaod << and i want it to behave like ostream, it should be able to take all the system defined types without any probelm
Kazoom
You're most likely out of luck .. if you need to know their types, then you have to overload for each type. If you just need a string-representation of your argument, then take a template argument and pass that onto std::stringstream. If you're unfamiliar with templates heres a very light intro: http://en.wikipedia.org/wiki/Template_%28programming%29#Function_templates
eduffy
+1  A: 

an i have just one overloaded operator method with one parameter(like void*) and then decide inside that method how to typecast integer to char*

No, you can't. A void * carries no type information, so there is no way of working out what type it actually points to.

anon
+1  A: 

There is just one overloaded function. It doesn't take a void *, because that would be useless. If it takes one data type, it isn't overloaded, and it only sees the input value after it's been converted to the type. That means you have no control over how to convert, say, an int.

If you want different behavior between, say, an int and a char *, you need to let the function know somehow what type it is getting, and you need to pass the value in. This is exactly what an overloaded or template function does.

David Thornley
David Rodríguez - dribeas
@dribease as shown in the example in the question what should i do to make my call to the overloaded operator take std::endl as parameter? i m not currently concerned about user defined types i only want my class to behave like ostream on system defined types
Kazoom
If you want it to behave like ostream, use ostream in the form of ostringstream. You can do it directly, getting the string value out with .str(), or create a template function that will accept a value of whatever type, feed it to an ostringstream, and return the string value.
David Thornley
+3  A: 

After re-reading your question (as a result of a comment in this answer) I have realized that what you want is not only conversions into string (my assumptions in the other answer here), but rather forwarding into the internal ofstream.

Now, what you want to achieve is not simple, and may be overkill in most cases. In the implementation of [make_string][3] that I have (that forwards to an internal ostringstream), I don't allow for manipulators to be passed. If the user wants to add a new line (we develop under linux) they just pass a '\n' character.

Your problem is forwarding manipulators (std::hex, std::endl...). Your operator<< is defined as taking a constant instance of a type T, but manipulators are function pointers and the compiler is not able to match it against your methods.

Manipulators are functions that operate on the std::basic_ostream template. The basic_ostream template and ostream class are defined as:

template <typename TChar, typename TTraits = char_traits<TChar> >
class basic_ostream;

typedef basic_ostream<char> ostream;
// or
// typedef basic_ostream<wchar_t> if using wide characters

Then the possible manipulators that can be passed to a std::ostream are:

typedef std::ostream& (*manip1)( std::ostream& );

typedef std::basic_ios< std::ostream::char_type, std::ostream::traits_type > ios_type;
typedef ios_type& (*manip2)( ios_type& );

typedef std::ios_base& (*manip3)( std::ios_base& );

If you want to accept manipulators you must provide that overload in your class:

class mystream
{
//...
public:
   template <typename T> 
   mystream& operator<<( T datum ) {
      stream << datum;
      return *this
   }
   // overload for manipulators
   mystream& operator<<( manip1 fp ) {
      stream << fp;
      return *this;
   }
   mystream& operator<<( manip2 fp ) {
      stream << fp;
      return *this;
   }
   mystream& operator<<( manip3 fp ) {
      stream << fp;
      return *this;
   }
};

In particular, the signature for endl (which may be the only one you require) is:

template <typename Char, typename Traits>
std::basic_ostream<Char,Traits>& 
   std::endl( std::basic_ostream<Char,Traits>& stream );

so it falls under the manip1 type of functions. Others, like std::hex fall under different categories (manip3 in this particular case)

David Rodríguez - dribeas
hex , dec , oct etc all fall into manip3, how do u differentiate between what actually made the call
Kazoom
Do you need to? Are you not just passing the argument into the internal stream? The library does not differentiate them, they are just function pointers. The operator<< overload in the basic_stream class will call the function passing `this` as argument.
David Rodríguez - dribeas
thanks, i m trying to use setw() but it does not seem to be falling in any of these 3 categories, any sugggestion sto handle this?
Kazoom
_setw_ is special in that the exact type of the element returned by the function call is implementation defined. With gcc, the function call returns an element of type \_Setw that is a struct containing the new width. Now, the standard does define that it must be equivalent to calling ios\_base::width, so you might want to consider defining an alternative way of forwarding the call to the inner stream.
David Rodríguez - dribeas