Is it possible to overload operator<< like this? [duplicate] - c++

This question already has answers here:
How to define a static operator<<?
(4 answers)
Closed 9 years ago.
Let's say I have a class called "Logger". The name is self explanatory, it logs stuff. I have a static method, which logs stuff (Logger::log(string msg)).
I wanted to overload the operator <<, so that I could do something like:
Logger << "AW YEAH, I LOVE C++";
I tried to do this, but couldn't. What I managed, was this:
Logger l;
l << ":(";
...
is it possible what I want to do? And if yes, how?
Thank You in advance :)

If Logger is the name of a class then of course you can't do that. Use something like
Logger &log() {
static Logger l;
return l;
}
log() << "And the answer is" << 42;

Assuming you want to leverage the output operators provide by std::ostream you should not try to overload the output operator! Instead, you'd create a suitable stream buffer (i.e., a class derived from std::streambuf) and implement your custom output logic in that class's overflow() and sync() methods. Your logger would then derive from std::ostream and initialize its base class to use your custom stream buffer.

Overloaded operators operate on values, not on types.
Maybe you should rename your class, and then create a suitable global object. For example:
logger.h:
class mylogger { /* ... */ };
extern mylogger logger;
logger.cpp:
#include "logger.h"
mylogger logger;
Usage:
#include "logger.h"
logger << "Done";
Beware of global initialization issues; though; check out your implementation of std::cout for a way to solve this (e.g. with a Schwartz counter).

It is possible, but you need to figure out what interface you really want. One option is to make your Logger be an std::ostream (inheritance) and then things would kind of work out of the box. The alternative is to maintain a logger that is unrelated (no inheritance) to std::ostream, but then you need to provide Logger& operator<<(Logger&,T const &) for any and all types T you want to log. For the particular case of std::string you could do:
Logger& operator<<(Logger& logger, std::string const& msg) {
logger.log(msg); // need not be, and problably should be static
return logger;
}
Making this generic involves as with most generic code in C++ the use of templates:
template <typename T>
Logger& operator<<(Logger& logger, T const & obj) {
// do specific work based on the type, or a completely generic approach:
std::ostringstream st;
st << obj;
logger.log(st.str());
return logger;
}
At this point you might want to consider adding support for manipulators and... well, if you start down this path, it might make more sense not to create the std::ostringstream in each function, but create a single one as a member, then dump all data into that stream and use some manipulator to extract the string and write it (for example on std::flush or std::ends...)
template <typename T>
Logger& operator<<(Logger& logger, T const& obj) {
logger.stream << obj;
return logger;
}
Logger& operator<<(Logger& logger, std::ostream& (*manip)(std::ostream&)) {
logger.stream << manip;
if (manip == static_cast<std::ostream& (*)(std::ostream&)>(std::flush)) {
logger.write(); // flush to disk
}
return logger;
}
// add support for other manipulators...
Then again you might start wondering if it would not be easier to pull some off the shelf logging library and just use it.

Related

Simplest way to create class that behaves like stringstream

I'm making a simple Error class that should be thrown using throw statement, logged or written in console. The basic idea of the usage is:
//const char* filename is function argument
if(!file_exists(filename))
throw Error(line, file, severity)<<"Invalid argument: the file does not exist: "<<filename;
I originally wanted to extend stringstream, but my searches indicate that it's impossible to extend on streams.
I'd really like to make the error class as convenient as you can see above, which means able to "eat" various types and append them to internal error message.
So actually it's not so hard. You can't inherit from stringstream directly - or I just didn't find out how. You'll soon drown in std template system...
template<class _Elem,
class _Traits,
class _Alloc>
// ... mom help me!
But, you can make a template:
template <class T>
Error& Error::operator<<(T const& value) {
//private std::stringstream message
message<<value;
//You can also trigger code for every call - neat, ain't it?
}
You'll be adding all values from this method to private variable within the class:
class Error
{
public:
Error(int, const char*, int);
~Error(void);
std::string file;
unsigned int line;
//Returns message.str()
std::string what();
//Calls message.operator<<()
template <class T>
Error& operator<< (T const& rhs);
private:
std::stringstream message;
};
There's still something I'm missing - how to distinguish between types supported by stringstream and others and throw error on the line of call, rather than in Error class. Also I'd like to write own handlers for unsupported types.

Return a non-temporary object from C++ function with limited life

I am writing a logging utility for my application. It was chosen to do so for some reasons. I want the logging to happen as
Logger logger;
...
logger.Info() << "This is log statement" << 1;
logger.Info() returns a another type (LogStream) that overloads << operator.
class Logger
{
public:
Logger(LogLevel level, LogWriter writer);
~Logger()
{
// Writes to Logwrite which sends logs to all appenders
}
template <class T>
LogStream& operator<<(const T& t)
{
m_output << t;
return *this;
}
private:
std::ostringstream m_output;
LogLevel m_loglevel;
}
class Logger
{
LogStream Info()
{
return LogStream(INFO, m_writer); // NOT RIGHT
}
}
Is there an right and elegant way to return a logstream instance by Info() call without extra copies and has a limited life time so that appenders log (statements) without waiting till objects are out of scope.
I question that you say something is not right about your code example. The temporary object will be destroyed at the end of the full-expression, unless bound to a reference -- this seems to me like exactly the right granularity to collect log information into an atomic message and then flush.
The only thing you need to do is customize the copy constructor to not copy the existing buffered data, because you don't want it duplicated in the log. Just copy the constructor parameters (the handle to the writer and the severity level).

Secure direct access to class members

I wonder if the following syntax can be "admitted" or if good practices consider this as coming from hell. The goal would be to add a level of protection to force the developer to be well-conscious of what he is doing. Here is the syntax :
class MyClass
{
public:
template<bool RemoveProtection = false>
inline std::ofstream& writeStream()
{
static_assert(RemoveProtection, "You're doing it wrong");
return _writeStream;
}
inline const std::ofstream& writeStream() const
{
return _writeStream;
}
protected:
std::ofstream _writeStream;
};
The use would be :
x.writeStream().good(); // <- OK
x.writeStream().put('c'); // <- NOT OK
x.writeStream<true>().put('c'); // <- OK
I find this as a convenient way to tell to the developer : "Beware, you are using a low-level function and you have to be careful with what you are doing". Is it a "acceptable" way of providing a direct access to class members with a kind of "protection" ? Is there other way of coding a such thing ?
Have a look at meagar's comment:
You're making your code ugly, harder to maintain and inconvenient for... what exactly? Define your interface. That is the interface to your class. Do not allow developers to bypass it by using some ridiculous template flag hackery. If you're writing code, you always have to know what you're doing. Having to explicitly type <true> to indicate you especially know what you're doing is just... very, very wrong-headed. Developers have documentation. They don't need training wheels and artificial restrictions, they need clear concise code that lets them get things done. – meagar 2012-10-06 02:41:53Z
A class you provide to others should never be able to get into an unpredicted state when another user uses it. An unpredicted state is in this case a state which you never considered when you were writing the class. As such you should either never allow access to low-level methods of your class or document possible flaws.
Lets say you're writing a logger:
struct MyLogger{
MyLogger(std::string filename) : stream(filename.c_str()){}
template <typename T>
MyLogger& operator<<(const T& v){ stream << v << " "; return *this;}
private:
std::ofstream stream;
};
Ignore that there isn't a copy constructor and that the assignment operand is missing. Also ignore that it's a crude logger, it doesn't even provide a timestamp. However, as you can see, the state of the logger depends completely on the logger's methods, e.g. if the file has been successfully opened it won't be closed until the logger gets destroyed.
Now say that we use your approach:
struct MyLogger{
MyLogger(std::string filename) : stream(filename.c_str()){}
template <typename T>
MyLogger& operator<<(const T& v){ stream << v << " "; return *this;}
template<bool RemoveProtection = false>
inline std::ofstream& writeStream()
{
static_assert(RemoveProtection, "You're doing it wrong");
return stream;
}
inline const std::ofstream& writeStream() const
{
return stream;
}
private:
std::ofstream stream;
};
And now someone uses the following code
logger.writeStream<true>.close();
Bang. Your logger is broken. Of course it's the users fault, since they used <true>, didn't they? But more often than not a user is going to copy example code, especially if he uses a library for the first time. The user sees your example
logger.writeStream().good(); // <- OK
logger.writeStream().put('c'); // <- NOT OK
logger.writeStream<true>().put('c'); // <- OK
and ignores the documentation completely at first. Then he's going to use the first and the last version. Later he discovers that the last version works every time! What a miraculous thing <true> is. And then he starts to blame you for evil things that happen, so you have protect yourself from blatant flames with a documentation which includes a warning:
/**
* \brief Returns a reference to the internal write stream
*
* \note You have to use the template parameter `<true>` in order to use it
*
* \warning Please note that this will return a reference to the internal
* write stream. As such you shouldn't create any state in which
* the logger cannot work, such as closing the stream.
*/
template<bool RemoveProtection = false>
inline std::ofstream& writeStream()
{
static_assert(RemoveProtection, "You're doing it wrong");
return stream;
}
So, what did we get? We still had to put that warning somewhere. It would have been much simpler if we made stream public:
struct MyLogger{
MyLogger(std::string filename) : stream(filename.c_str()){}
template <typename T>
MyLogger& operator<<(const T& v){ stream << v << " "; return *this;}
/**
* The internal write stream. Please look out that you don't create
* any state in which the logger cannot work, such as closing the stream.
*/
std::ofstream stream;
};
or sticked to
/** >put warning here< */
inline std::ofstream & writeStream()
{
return stream;
}
Woops. So either don't allow access to your low-level methods (build a wrapper to specific std::ofstream methods if they should be allowed to use them) or document the possible flaws which can happen if you alter the object's internals to much, but don't go the middle-way and make it look okay with a static_assert.

Conditional output

I'd like to create a C++ ostream object that only outputs anything if a condition holds true, to use for debugging. What would be the easiest way to do this? I know that boost has classes that make this easy, but I'd like to know if there's a simple way to do it without boost. The documentation makes it seem like subclassing ostream::sentry would make this possible, but I can't find any source saying that's something that you can/should do.
Don't subclass, it's easier to use a wrapper:
class MaybeOstream
{
public:
MaybeOstream(std::ostream& stream_) : stream(stream_), bOutput(true) {}
void enable(bool bEnable) { bOutput = bEnable; }
template<typename T>
MaybeOstream& operator<< (T x)
{
if(bOutput)
stream << x;
return *this;
}
// Add other wrappers around ostream: operator void*, good(), fail(),
// eof(), etc., which just call through to the ostream
private:
std::ostream& stream;
bool bOutput;
}
Take a look at this paper on filtered streambufs.

Using a virtually inherited function non-virtually?

I have run into trouble trying to implement functionality for serializing some classes in my game. I store some data in a raw text file and I want to be able to save and load to/from it.
The details of this, however, are irrelevant. The problem is that I am trying to make each object that is interesting for the save file to be able to serialize itself. For this I have defined an interface ISerializable, with purely virtual declarations of operator<< and operator>>.
The class Hierarchy looks something like this
-> GameObject -> Character -> Player ...
ISerializable -> Item -> Container ...
-> Room ...
This means there are many possible situations for serializing the objects of the different classes. Containers, for instance, should call operator<< on all contained items.
Now, since operator>> is virtual, i figured if I wanted to serialize something that implements the functionality defined in ISerializable i could just do something like
ostream & Player::operator<<(ostream & os){
Character::operator<<(os);
os << player_specific_property 1 << " "
<< player_specific_property 2 << "...";
return os;
}
and then
ostream & Character::operator<<(ostream & os){
GameObject::operator<<(os);
os << character_specific_property 1 << " "
<< character_specific_property 2 << "...";
return os;
}
but I quickly learnt that this first attempt was illegal. What I'm asking here is how do I work around this?
I don't feel like implementing a function manually for each class. I guess I'm looking for something like the super functionality from Java.
Any help is appreciated.
-- COMMENTS ON EDIT ------------
Alright, last time I was in a hurry when I was writing the question. The code is now more like it was when I tried to compile it. I fixed the question and the problem I had was unrelated to the question asked. I'm ashamed to say it was caused by an error in the wake of a large refactoring of the code, and the fact that the operator was not implemented in every base class.
Many thanks for the replies however!
The problem is not in your attempt to call a virtual function non-virtually. The problem is this line: os = Character::operator<<(os);. That is an assignment, but std::ostream doesn't have an operator=.
You don't need the assignment anyway. The stream returned is the same stream as the stream you pass in. The only reason it's returned is so you can chain them.
Hence the fix is to just change the code to
ostream & Player::operator<<(ostream & os){
Character::operator<<(os);
os << player_specific_property 1 << " "
<< player_specific_property 2 << "...";
return os;
}
This is not how overloading operator<< for ostream works. The left-hand operator is an ostream (hence you gotta overload it as a free function) and the right-hand operator is your object (which is why the virtual mechanism wouldn't easily work.
I suppose you could try:
class Base
{
//...
virtual std::ostream& output(std::ostream&) const;
};
std::ostream& operator<< (std::ostream& os, const Base& obj)
{
return obj.output(os);
}
Now a derived class naturally might call the output method of its parent(s):
class Derived: public Base
//...
virtual std::ostream& output(std::ostream& os) const
{
Base::output(os);
return os << my_specific_data;
}
};