I'm trying to write a simple logging function which can handle different types in this format:
LOG("This is one type: " << one_type << " and here is a different type: " << diff_type);
I've been looking at the examples here:
How to use my logging class like a std C stream?
stringstream with recursive variadic function?
and this is what I came up with:
#include <iostream>
#include <sstream>
void LOG(std::stringstream& ss)
{
std::cout << ss.str() << std::endl;
}
However, even when I just do:
LOG("Some text");
I get the error:
could not convert ‘(const char*)"Some text"’ from ‘const char*’ to ‘std::stringstream’ {aka ‘std::__cxx11::basic_stringstream<char>’}
How can I implement this?
CodePudding user response:
A common way to solve this is to make LOG
a macro that just does text substitution instead. You could define a LOG
macro like
#define LOG(to_log) \
do \
{ \
std::cout << to_log << std::endl; \
} while (false)
and then
LOG("This is one type: " << one_type << " and here is a different type: " << diff_type);
would get expanded to
do
{
std::cout << "This is one type: " << one_type << " and here is a different type: " << diff_type << std::endl;
} while (false);
CodePudding user response:
template <typename ... T>
void log(T const& ... t)
{
( std::cout << ... << t );
// maybe want to add a newline?
std::cout << std::endl; // note: '\n' just adds it,
// std::endl flushes the stream...
}
would allow to log (to console!) as:
log("this is an int: ", 1210, " and this is a double: ", 10.12);
Note the commas instead of the stream operator (<<
)...
If you want to log to arbitrary streams you might need to add it as yet another parameter (/*...*/ void log(std::ostream& s, T const&... t)
) or you might (among other solutions) initialise some singleton that you access from within the logging function:
void initialiseLogging(std::ostream& s)
{
Logger::instance().initialize(s);
}
template <typename ... T>
void log(T const& ... t)
{
// assumes returning a reference:
( Logger::instance().stream() << ... << t );
}
Above variant assumes initialisation being required and logging without yielding undefined behaviour (needs to be documented!). If you want to be able to log without you need to change:
{
// now assuming a pointer being returned!
auto s = Logger::instance().stream();
// variant 1: log to nowhere if not initialised:
if(s)
{
( *s << ... << t );
}
// variant 2: default logging to console
s = s ? s : &std::cout;
( *s << ... << t );
}