overload stream operator for function - c++

I am curious if it is possible to overload a << stream operator for a function?
I am using OutputDebugString on windows to write to the log, and it only accepts strings.
I am wondering if I can write a function in c++ where I could wrap OutputDebugString and do the following
MyLogFuntion() << string << int << char;

You can return an object from your function that has operator << and then do the logging in the object's destructor. Then when you call MyLogFunction() it will create a temporary object which will store all the data inserted into it and then output it when the object is goes out of scope at the end of the statement.
Here's an example (without The logger function which is actually redundant)
#include <iostream>
#include <sstream>
class Logger {
std::stringstream ss;
public:
~Logger() {
// You want: OutputDebugString(ss.str());
std::cout<< ss.str();
}
// General for all types supported by stringstream
template<typename T>
Logger& operator<<(const T& arg) {
ss << arg;
return *this;
}
// You can override for specific types
Logger& operator<<(bool b) {
ss << (b? "Yep" : "Nope");
return *this;
}
};
int main() {
Logger() << "Is the answer " << 42 << "? " << true;
}
Output:
Is the answer 42? Yep

You cannot provide overloads in the way you would like to.
If the method you have to use (OutputDebugString in your case) forces you to provide a std::string (or similar) parameter, you'll have to provide that parameter somehow. One way is to use a std::stringstream, stream into that, and then pass the result to OutputDebugString:
std::stringstream ss;
ss << whatever << " you " << want << to << stream;
OutputDebugString(ss.str());
You could also dump this into a macro if you really want things more compact:
#define OUTPUT_DEBUG_STRING(streamdata) \
do { \
std::stringstream ss; \
ss << streamdata; \
} while (0)
And then write
OUTPUT_DEBUG_STRING(whatever << " you " << want << to << stream);
Another alternative is to write a more complex wrapper class around OutputDebugString which provides stream operators. But that is probably not going to be worth the effort.

Related

Is it possible to create a C++ class that mimics the std::cout syntax by chaining overloaded insertion operators the same way that easylogging++ does?

The easylogging++ code defines a macro that makes it very simple to use:
LOG(logLevel) << "This mimics std::cout syntax. " << 1 << " + " << 1 << " = " << 2;
I want to make a wrapper class for easylogging++. I can easily create a function with two parameters to wrap the above line. However, is it possible to mimic this syntax in a wrapper class? For example:
Logger logger;
logger(logLevel) << "Line " << 1 << " of log text.";
I know I can easily overload the insertion operator, but that still leaves me with having to write another function to set the log level each time.
UPDATE:
Thanks to Starl1ght's answer I was able to get this working. I figured I would share in case anyone else has a similar need.
I created two overloads. One was for () and the other for <<.
Logger &operator()(logLevelT logLevel) {
mLogLevel = logLevel;
return *this;
}
template <typename T>
Logger &operator<<(T const &value) {
LOG(mLogLevel) << value;
return *this;
}
UPDATE 2:
I wanted to update this post again to give my reasoning and show my final solution.
My reasoning is that my project is a demonstration of abstraction. I'm trying to demonstrate that logging libraries (and many other things) can be abstracted away from the core functionality of your software. This also makes the software components modular. This way I can swap out the easylogging++ library without loosing the syntax because it is implemented in the module interface.
My last update didn't mention how I overcame the obstacle of insertion chaining, so I wanted to post an example to show how I did it. The following code is a simplified example of how to achieve std::cout like syntax for a class.
#include <iostream> // For cout
#include <string> // For strings
#include <sstream> // For ostringstream
enum logLevelT {
INFO_LEVEL,
WARNING_LEVEL,
ERROR_LEVEL,
FATAL_LEVEL
};
class Logger {
private:
std::string logName;
public:
Logger(std::string nameOfLog, std::string pathToLogFile) {
logName = nameOfLog;
//TODO Configure your logging library and instantiate
// an instance if applicable.
}
~Logger(){}
// LogInputStream is instantiated as a temporary object. It is used
// to build the log entry stream. It writes the completed stream
// in the destructor as the object goes out of scope automatically.
struct LogInputStream {
LogInputStream(logLevelT logLevel, std::string nameOfLog) {
currentLogLevel = logLevel;
currentLogName = nameOfLog;
}
// Copy Constructor
LogInputStream(LogInputStream &lis) {
currentLogLevel = lis.currentLogLevel;
currentLogName = lis.currentLogName;
logEntryStream.str(lis.logEntryStream.str());
}
// Destructor that writes the log entry stream to the log as the
// LogInputStream object goes out of scope.
~LogInputStream() {
std::cout << "Logger: " << currentLogName
<< " Level: " << currentLogLevel
<< " logEntryStream = " << logEntryStream.str()
<< std::endl;
//TODO Make a log call to your logging library. You have your log level
// and a completed log entry stream.
}
// Overloaded insertion operator that adds the given parameter
// to the log entry stream.
template <typename T>
LogInputStream &operator<<(T const &value) {
logEntryStream << value;
return *this;
}
std::string currentLogName;
logLevelT currentLogLevel;
std::ostringstream logEntryStream;
};
// Overloaded function call operator for providing the log level
Logger::LogInputStream operator()(logLevelT logLevel) {
LogInputStream logInputStream(logLevel, logName);
return logInputStream;
}
// Overloaded insertion operator that is used if the overloaded
// function call operator is not used.
template <typename T>
Logger::LogInputStream operator<<(T const &value) {
LogInputStream logInputStream(INFO_LEVEL, logName);
logInputStream << value;
return logInputStream;
}
};
int main(int argc, char *argv[]) {
Logger logger1 = Logger("Logger1", "/path/to/log.log");
Logger logger2 = Logger("Logger2", "/path/to/log.log");
logger1(INFO_LEVEL) << "This is the " << 1 << "st test";
logger2(ERROR_LEVEL) << "This is the " << 2 << "nd test";
logger2 << "This is the " << 3 << "rd test";
return 0;
}
I feel like I could have done a better job with the naming and the comments but I am pressed for time. I'm definitely open to any comments or critiques.
You must overload operator() so, it will set internal log level and return *this as type Logger&, so, overloaded operator<< will work on returned reference with necessary log-level set.
Something like this:
Logger& Logger::operator()(LogLevel level) {
// set internal log level
return *this;
}

How to write iostream-like interface to logging library?

I would like to write a convinient interface to my very simple logging library. Take two following pieces of code. The first one is what I do now, the second one is my idea for an intuitive interface:
std::ostringstream stream;
stream<<"Some text "<<and_variables<<" formated using standard string stream"
logger.log(stream.str()); //then passed to the logger
And
logger.convinient_log()<<"Same text "<<with_variables<<" but passed directly";
My thought-design process behind that idea is to return some kind of temporary stringstream-like object from logger.convinient_log() function. That object on destruction (I hope it happens at the end of the line or in a similar, convinient place) would collect string from itself and call an actual logger.log(). The point is I want to process it whole, not term-by-term, so that log() can add eg. prefix and sufix to whole line of text.
I'm very well avare that it might be straight impossible or impossible without some heavy magic. If that's the case, what would be an almost-as-convinient way to do that and how to implement it? I bet on passing some special variable that would force collect-call-logger.log() operation.
If you don't know an exact answer, resources on the topic (eg. extending stringstream) would be also welcome.
This is how Boost.Log works, for example. The basic idea is simple:
struct log
{
log() {
uncaught = std::uncaught_exceptions();
}
~log() {
if (uncaught >= std::uncaught_exceptions()) {
std::cout << "prefix: " << stream.str() << " suffix\n";
}
}
std::stringstream stream;
int uncaught;
};
template <typename T>
log& operator<<(log& record, T&& t) {
record.stream << std::forward<T>(t);
return record;
}
template <typename T>
log& operator<<(log&& record, T&& t) {
return record << std::forward<T>(t);
}
// Usage:
log() << "Hello world! " << 42;
std::uncaught_exceptions() is used to avoid logging an incomplete message if an exception is thrown in the middle.
Here's a class I've togeather a while ago. It sounds like what you're looking for is this. I was able to achieve it without any daunting inheriting of ostreams, stream_buf or anything else. You can write to files, console, sockets, or whatever you want whenever a flush is caught.
It doesn't work with ostream_iterators but handles all of the io_manip functions well.
Usage:
Logger log;
int age = 32;
log << "Hello, I am " << age << " years old" << std::endl;
log << "That's " << std::setbase(16) << age << " years in hex" << std::endl;
log(Logger::ERROR) << "Now I'm logging an error" << std::endl;
log << "However, after a flush/endl, the error will revert to INFO" << std::end;
Implementation
#include <iostream>
#include <sstream>
#include <string>
class Logger
{
public:
typedef std::ostream& (*ManipFn)(std::ostream&);
typedef std::ios_base& (*FlagsFn)(std::ios_base&);
enum LogLevel
{
INFO,
WARN,
ERROR
};
Logger() : m_logLevel(INFO) {}
template<class T> // int, double, strings, etc
Logger& operator<<(const T& output)
{
m_stream << output;
return *this;
}
Logger& operator<<(ManipFn manip) /// endl, flush, setw, setfill, etc.
{
manip(m_stream);
if (manip == static_cast<ManipFn>(std::flush)
|| manip == static_cast<ManipFn>(std::endl ) )
this->flush();
return *this;
}
Logger& operator<<(FlagsFn manip) /// setiosflags, resetiosflags
{
manip(m_stream);
return *this;
}
Logger& operator()(LogLevel e)
{
m_logLevel = e;
return *this;
}
void flush()
{
/*
m_stream.str() has your full message here.
Good place to prepend time, log-level.
Send to console, file, socket, or whatever you like here.
*/
m_logLevel = INFO;
m_stream.str( std::string() );
m_stream.clear();
}
private:
std::stringstream m_stream;
int m_logLevel;
};
Create a custom class derived from std::basic_streambuf to write to your logger, eg:
class LoggerBuf : public std::stringbuf
{
private:
Logger logger;
public:
LoggerBuf(params) : std::stringbuf(), logger(params) {
...
}
virtual int sync() {
int ret = std::stringbuf::sync();
logger.log(str());
return ret;
}
};
And then you can instantiate a std::basic_ostream object giving it a pointer to a LoggerBuf object, eg:
LoggerBuf buff(params);
std::ostream stream(&buf);
stream << "Some text " << and_variables << " formated using standard string stream";
stream << std::flush; // only if you need to log before the destructor is called
Alternatively, derive a custom class from std::basic_ostream to wrap your LoggerBuf class, eg:
class logger_ostream : public std::ostream
{
private:
LoggerBuf buff;
public:
logger_ostream(params) : std:ostream(), buff(params)
{
init(&buff);
}
};
std::logger_ostream logger(params);
logger << "Some text " << and_variables << " formated using standard string stream";
logger << std::flush; // only if you need to log before the destructor is called

C++ Using stringstream after << as parameter

Is it possible to write a method that takes a stringstream and have it look something like this,
void method(string str)
void printStringStream( StringStream& ss)
{
method(ss.str());
}
And can be called like this
stringstream var;
printStringStream( var << "Text" << intVar << "More text"<<floatvar);
I looked up the << operator and it looks like it returns a ostream& object but I'm probably reading this wrong or just not implementing it right.
Really all I want is a clean way to concatenate stuff together as a string and pass it to a function. The cleanest thing I could find was a stringstream object but that still leaves much to be desired.
Notes:
I can't use much of c++11 answers because I'm running on Visual Studio 2010 (against my will, but still)
I have access to Boost so go nuts with that.
I wouldn't be against a custom method as long as it cleans up this mess.
Edit:
With #Mooing Duck's answer mixed with #PiotrNycz syntax I achieved my goal of written code like this,
try{
//code
}catch(exception e)
{
printStringStream( stringstream() << "An exception has occurred.\n"
<<" Error: " << e.message
<<"\n If this persists please contact "<< contactInfo
<<"\n Sorry for the inconvenience");
}
This is as clean and readable as I could have hoped for.
Hopefully this helps others clean up writing messages.
Ah, took me a minute. Since operator<< is a free function overloaded for all ostream types, it doesn't return a std::stringstream, it returns a std::ostream like you say.
void printStringStream(std::ostream& ss)
Now clearly, general ostreams don't have a .str() member, but they do have a magic way to copy one entire stream to another:
std::cout << ss.rdbuf();
Here's a link to the full code showing that it compiles and runs fine http://ideone.com/DgL5V
EDIT
If you really need a string in the function, I can think of a few solutions:
First, do the streaming seperately:
stringstream var;
var << "Text" << intVar << "More text"<<floatvar;
printStringStream(var);
Second: copy the stream to a string (possible performance issue)
void printStringStream( ostream& t)
{
std::stringstream ss;
ss << t.rdbuf();
method(ss.str());
}
Third: make the other function take a stream too
Make your wrapper over std::stringstream. In this new class you can define whatever operator << you need:
class SSB {
public:
operator std::stringstream& () { return ss; }
template <class T>
SSB& operator << (const T& v) { ss << v; return *this; }
template <class T>
SSB& operator << (const T* v) { ss << v; return *this; }
SSB& operator << (std::ostream& (*v)(std::ostream&)) { ss << v; return *this; }
// Be aware - I am not sure I cover all <<'s
private:
std::stringstream ss;
};
void print(std::stringstream& ss)
{
std::cout << ss.str() << std::endl;
}
int main() {
SSB ssb;
print (ssb << "Hello" << " world in " << 2012 << std::endl);
print (SSB() << "Hello" << " world in " << 2012 << std::endl);
}
For ease of writing objects that can be inserted into a stream, all these classes overload operator<< on ostream&. (Operator overloading can be used by subclasses, if no closer match exists.) These operator<< overloads all return ostream&.
What you can do is make the function take an ostream& and dynamic_cast<> it to stringstream&. If the wrong type is passed in, bad_cast is thrown.
void printStringStream(ostream& os) {
stringstream &ss = dynamic_cast<stringstream&>(os);
cout << ss.str();
}
Note: static_cast<> can be used, it will be faster, but not so bug proof in the case you passed something that is not a stringstream.
Since you know you've got a stringstream, just cast the return value:
stringstream var;
printStringStream(static_cast<stringstream&>(var << whatever));
Just to add to the mix: Personally, I would create a stream which calls whatever function I need to call upon destruction:
#include <sstream>
#include <iostream>
void someFunction(std::string const& value)
{
std::cout << "someFunction(" << value << ")\n";
}
void method(std::string const& value)
{
std::cout << "method(" << value << ")\n";
}
class FunctionStream
: private virtual std::stringbuf
, public std::ostream
{
public:
FunctionStream()
: std::ostream(this)
, d_function(&method)
{
}
FunctionStream(void (*function)(std::string const&))
: std::ostream(this)
, d_function(function)
{
}
~FunctionStream()
{
this->d_function(this->str());
}
private:
void (*d_function)(std::string const&);
};
int main(int ac, char* av[])
{
FunctionStream() << "Hello, world: " << ac;
FunctionStream(&someFunction) << "Goodbye, world: " << ac;
}
It is worth noting that the first object sent to the temporary has to be of a specific set of types, namely one of those, the class std::ostream knows about: Normally, the shift operator takes an std::ostream& as first argument but a temporary cannot be bound to this type. However, there are a number of member operators which, being a member, don't need to bind to a reference! If you want to use a user defined type first, you need to extract a reference temporary which can be done by using one of the member input operators.

Managing a log stream in C++ in a cout-like notation

I have a class in c++ in order to write log files for an application of mine. I have already built the class and it works, it is something like this:
class Logger {
std::string _filename;
public:
void print(std::string tobeprinted);
}
Well, it is intuitive that, in order to print a line in the log file, for an object of Logger, it is simply necessary to do the following:
Logger mylogger("myfile.log");
mylogger.print(std::string("This is a log line"));
Well. Using a method approach is not the same as using a much better pattern like << is.
I would like to do the following:
Logger mylogger("myfile.log");
mylogger << "This is a log line";
That's all. I suppose I must overload the << operator... But overloading using this signature (the classic one):
ostream& operator<<(ostream& output, const MyObj& o);
But I do not have a ostream...
So, should I do as follows?
Logger& operator<<(Logger& output, const std::string& o);
Is this the right way?
Thanks
class Log
{
public:
enum Level { Debug, Error, Info };
static ostream& GetStream() { return cout; }
static bool IsLevelActive(Level l) { return true; }
};
#ifndef NO_LOG
#define LOG_ERROR(M) do { if (Log::IsLevelActive(Log::Error)) (Log::GetStream() << "ERR: " << M << "\n"); } while (false)
#define LOG_INFO(M) do { if (Log::IsLevelActive(Log::Info)) (Log::GetStream() << "INF: " << M << "\n"); } while (false)
#define LOG_WARNING(M) do { if (Log::IsLevelActive(Log::Warning)) (Log::GetStream() << "WRN: " << M << "\n"); } while (false)
#else
#define LOG_ERROR(M)
#define LOG_INFO(M)
#define LOG_WARNING(M)
#endif
struct MyObject {
int a, b;
};
ostream& operator<<(ostream& ostr, const MyObject& obj) {
ostr << "(a=" << obj.a << ", b=" << obj.b << ")";
return ostr;
}
void test() {
int v1 = 42;
int v2 = 43;
LOG_INFO("value1=" << v1 << ", value2=" << v2);
MyObject o = {1, 2};
LOG_INFO("obj=" << o);
}
Why not simply make Logger a sub-class of either std::ostream or std::ostringstream? Then all that functionality will already be implemented.
Yes, this is the right way. But you'll have to add << operator overloads for every data type that you need to log.
You don't really want to create whole new streams, as you then need to redefine all the stream operators. You'd only do that if you want to change entirely how data gets converted into character data. (Ick).
What I've found best for this is to create a class that will keep track of a stream and send its contents to a destination of my choice (the logger) when destructed. That, combined with a smattering of macros, gives you what you are looking for: stream syntax for logging.
Boost actually has some classes that help with this. Look at iostreams.

Turning temporary stringstream to c_str() in single statement

Consider the following function:
void f(const char* str);
Suppose I want to generate a string using stringstream and pass it to this function. If I want to do it in one statement, I might try:
f((std::ostringstream() << "Value: " << 5).str().c_str()); // error
This gives an error: 'str()' is not a member of 'basic_ostream'. OK, so operator<< is returning ostream instead of ostringstream - how about casting it back to an ostringstream?
1) Is this cast safe?
f(static_cast<std::ostringstream&>(std::ostringstream() << "Value: " << 5).str().c_str()); // incorrect output
Now with this, it turns out for the operator<<("Value: ") call, it's actually calling ostream's operator<<(void*) and printing a hex address. This is wrong, I want the text.
2) Why does operator<< on the temporary std::ostringstream() call the ostream operator? Surely the temporary has a type of 'ostringstream' not 'ostream'?
I can cast the temporary to force the correct operator call too!
f(static_cast<std::ostringstream&>(static_cast<std::ostringstream&>(std::ostringstream()) << "Value: " << 5).str().c_str());
This appears to work and passes "Value: 5" to f().
3) Am I relying on undefined behavior now? The casts look unusual.
I'm aware the best alternative is something like this:
std::ostringstream ss;
ss << "Value: " << 5;
f(ss.str().c_str());
...but I'm interested in the behavior of doing it in one line. Suppose someone wanted to make a (dubious) macro:
#define make_temporary_cstr(x) (static_cast<std::ostringstream&>(static_cast<std::ostringstream&>(std::ostringstream()) << x).str().c_str())
// ...
f(make_temporary_cstr("Value: " << 5));
Would this function as expected?
You cannot cast the temporary stream to std::ostringstream&. It is ill-formed (the compiler must tell you that it is wrong). The following can do it, though:
f(static_cast<std::ostringstream&>(
std::ostringstream().seekp(0) << "Value: " << 5).str().c_str());
That of course is ugly. But it shows how it can work. seekp is a member function returning a std::ostream&. Would probably better to write this generally
template<typename T>
struct lval { T t; T &getlval() { return t; } };
f(static_cast<std::ostringstream&>(
lval<std::ostringstream>().getlval() << "Value: " << 5).str().c_str());
The reason that without anything it takes the void*, is because that operator<< is a member-function. The operator<< that takes a char const* is not.
A temporary cannot be passed as a non-const reference to a function, that's why it does not find the correct streaming operator and instead takes the one with void* argument (it is a member function and thus calling it on a temporary is OK).
What comes to getting around the limitations by casting, I have a feeling that it is in fact UB, but I cannot say for sure. Someone else will surely quote the standard.
This can be done using a C++11 lambda function.
#include <iostream>
#include <sstream>
void f(const char * str)
{
std::cout << str << std::endl;
}
std::string str(void (*populate)(std::ostream &))
{
std::ostringstream stream;
populate(stream);
return stream.str();
}
int main(int argc, char * * args)
{
f(str([](std::ostream & ss){ ss << "Value: " << 5; }).c_str());
return 0;
}
// g++ -std=c++11 main.cpp -o main
// ./main
// Value: 5
If you like one_lined statements you can write:
// void f(const char* str);
f(static_cast<ostringstream*>(&(ostringstream() << "Value: " << 5))->str());
However you should prefer easier to maintain code as:
template <typename V>
string NumberValue(V val)
{
ostringstream ss;
ss << "Value: " << val;
return ss.str();
}
f(NumberValue(5));
I use something a bit like this for logging.
#include <sstream>
using namespace std;
const char *log_text(ostringstream &os, ostream &theSame)
{
static string ret; // Static so it persists after the call
ret = os.str();
os.str(""); // Truncate so I can re-use the stream
return ret.c_str();
}
int main(int argc, char **argv)
{
ostringstream ss;
cout << log_text(ss, ss << "My first message") << endl;
cout << log_text(ss, ss << "Another message") << endl;
}
Output:
My first message
Another message
Since C++17 we have folding expressions for templates that can be used to make generic string formatter that can accept everything that have stream support:
template <class... Args>
std::string format(Args &&... args)
{
std::ostringstream ostr;
(ostr << ... << args);
return ostr.str();
}
The you can use it like: format("Int number: ", 42, " Float number: ", 3.14).c_str().
In C++20 std::format is coming.