Simpler logger function using std::stringstream - c++

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?

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);

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 );
}

Related

What is causing this to fail to compile? Is it the declaration signature or is it within the implementation of the function itself?

I'm working on my Component class's member function Component::connect(). Component is an abstract base class for all other component types within my library.
I'm now in the process of modifying this method to make use of Variadic Function Templates and SFINAE to allow unknown multiple inputs into this function... All inputs must be derived from a Component type.
I'm having issues with the syntax for its declaration as well as its implementation... I've tried various things while getting various compiler errors. It might have something to do with Parameter Pack expansion or how I'm trying to use SFINAE within its signature.
Here is the current signature of my class and function that I'm working on...
class Component {
protected:
std::string id_ = "";
std::list<std::shared_ptr<Component>> components_;
explicit Component(const std::string& id) : id_{ id } {}
public:
virtual ~Component() {}
std::string& id() { return id_; }
// Trying to use both Variadic Function Template and SFINAE for this function!
// I may eventually remove this from here and move it to another class using CRTP...
template<typename ... Args, std::enable_if_t <std::is_class<Args...>{}, Component> = 0 >
void connect(Args&& ...args) {
for (auto& l : components_) {
if (args->id_ == l->id()) {
std::cout << "Component " << (args->id_) << " already exists in " << id_ << "!\n";
return;
}
}
components_.push_back( std::make_shared<Component>( args... ) );
std::cout << "Successfully connected " << args->id() << " to " << id_ << "\n";
}
virtual std::list<std::shared_ptr<Component>> myConnections() { return components_; }
virtual void propagate() {};
};
What would be the proper syntax to be able to successfully compile this in Visual Studio 2017 using C++17? I'm trying to utilize both Variadic Function templates with the use of SFINAE.
Edit
Before I changed my signature, derived classes such as Wire that are derived from Component I was able to use them like this:
Wire w1, w2, w3, w4;
w1.connect(&w2);
w1.connect(&w3);
w1.connect(&w4);
w2.connect(&w3);
w2.connect(&w4);
I would like to use this same function but in this manner:
w1.connect(&w2, &w3, &w4);
This is why I want to use a Variadic Function Template, and why I want to use SFINAE to make sure that any type that is passed into ::connect(), in which all derived classes can use it, is in fact derived from Component!
Not sure to understand what do you exactly want (and without a full example is more difficult) but...
All inputs must be derived from a Component type.
So, if I understand correctly (and given you tagged C++17, so you can use folding), the signature of the method should be
template <typename ... Args,
std::enable_if_t<(... && std::is_base_of<Component, Args>{}),
int> = 0>
void connect (Args && ... args)
or maybe
template <typename ... Args>
std::enable_if_t<(... && std::is_base_of<Component, Args>{})>
connect (Args && ... args)
I'm having issues with the syntax for its declaration as well as its implementation...
About the implementation, I suppose the bigger problem is the cycle; maybe you can try with
for ( auto & l : components_ )
{
std::string aid;
if ( true == ( ... || (args->id_ == l->id()
? (aid = args->id_, true)
: false) ) )
{
std::cout << "Component " << aid
<< " already exists in " << id_ << "!\n";
return;
}
}
or maybe
for ( auto & l : components_ )
{
std::string aid;
( ... , (args->id_ == l->id() ? aid = args->id_ : args->id_) );
if ( false == aid.empty() )
{
std::cout << "Component " << aid
<< " already exists in " << id_ << "!\n";
return;
}
}
or something similar.
But about
std::cout << "Successfully connected " << args->id() << " to " << id_ << "\n";
frankly... I don't know.
error: expression contains unexpanded parameter pack 'args'
if (args->id_ == l->id()) {
You could split up connect() in two functions to deal with the currently unexpanded parameter pack. One function that does the checking and connects and one that uses a fold expression:
template<typename T> // connect one only
void connect(T&& arg) {
static_assert(std::is_base_of_v<Component, std::remove_reference_t<T>>,
"Must be based on Component");
for (auto& l : components_) {
if (arg.id_ == l->id()) {
std::cout << "Component " << arg.id_ << " already in " << id_ << "\n";
return;
}
}
components_.push_back( std::make_shared<Component>( std::forward<T>(arg) ) );
std::cout << "Successfully connected " << arg.id() << " to " << id_ << "\n";
}
template<typename... Args> // folding
void connect(Args&& ...args) {
(connect(std::forward<Args>(args)), ...);
}
Connecting would then be done like so:
w1.connect(w2, w3, w4);
Demo (with bits from an old revision of your question)

Unable to concat strings in C++?

I have a method to log with the following definition:
void log(std::string s) {
std::string tag = "main";
std::cout << tag << " :" << s << std::endl;
}
I'm trying to call this method like this:
log("direction" << std::to_string(direction) << ", count: " << std::to_string(count));
direction and count are integers.
I'm getting this following error with << underlined in red:
no operator << matches these operands.
operand types are const char [10] << std::string
I have #include<string> in my header to make sure my strings are working as they should.
I tried std::string("direction") and still the issue was same.
Beginner in C++. Help would be appreciated.
operator<< isn't used for arbitrary string concatenation - it is called an "output stream operator", and it is only used in the context of std::ostream.
When you say...
std::cout << tag << " :" << s << std::endl;
...you're actually writing code roughly equivalent to:
std::cout.operator<<(tag).operator<<(" :").operator<<(s).operator<<(std::endl);
As you can see operator<< knows how to work with std::cout and std::string, but not between strings.
In order to concatenate std::string instances, you can simply use operator+:
log("direction" + std::to_string(direction) + ", count: " + std::to_string(count));
Please note that this concatenation technique is not the most efficient: you might want to look into std::stringstream or simply use std::string::reserve to avoid unnecessary memory allocations.
Substitute the << with the + operator as you are manipulating the string, not the stream:
log("direction" + std::to_string(direction) + ", count: " + std::to_string(count));
If you're determined to use the operator<< notation you need an object that understands it.
Here's such an object (I make no claims that this is a good idea):
#include <string>
#include <sstream>
#include <iostream>
void log(std::string s) {
std::string tag = "main";
std::cout << tag << " :" << s << std::endl;
}
struct string_accumulator
{
std::ostringstream ss;
template<class T>
friend string_accumulator& operator<<(string_accumulator& sa, T const& value)
{
sa.ss << value;
return sa;
}
template<class T>
friend string_accumulator& operator<<(string_accumulator&& sa, T const& value)
{
return operator<<(sa, value);
}
operator std::string () { return ss.str(); }
};
inline auto collect() -> string_accumulator
{
return string_accumulator();
}
int main()
{
int direction = 1;
int count = 1;
log(collect() << "direction" << std::to_string(direction) << ", count: " << std::to_string(count));
}
The prototype of your function is void log(std::string s);. It awaits for an std::string. So you need to pass a string to it, not a stream!
So, change this:
log("direction" << std::to_string(direction) << ", count: " << std::to_string(count));
to this:
log("direction" + std::to_string(direction) + ", count: " + std::to_string(count));
where I only changed the << operator to + operator. It will now concatenate everything inside the parentheses to a single std::string.
Your attempt implies that you wanted to pass std::ostream as the parameter. Maybe you want to read C++ Passing ostream as parameter. However, if I were you, I would just overload <<.
why don't you use:
// just include thisusing namespace std;

Processing all passed overloads at once

I'm tired of making up on the spot debug codes and including <iostream> in every single file. So I wanted to make myself a universal, self-contained and lightweight debug class, that I would just include in the header, and forget.
I want to use something along the lines of
#include "debug.hpp"
debug DBG;
DBG << "foo and" << " bar";
//Or even better, just include it and do debug() << "foo and" << " bar";
So, I wrote this:
#include <iostream>
#include <string>
#include <chrono>
#include <ctime>
class Debug
{
public:
Debug &operator<<(std::string arg_0)
{
auto tempTime = std::chrono::system_clock::to_time_t(
std::chrono::system_clock::now() );
auto timeString(ctime(&tempTime));
timeString = timeString.substr(timeString.find(':') - 2, 8);
std::cout << timeString << " >> " << arg_0 << '\n';
return *this;
}
};
But of course, this doesn't work because, as I've learned, every overload operator causes this function (is it still called a function?) to trigger separately. Creating:
hour:minute:second >> foo and
hour:minute:second >> bar
Any way I could pass everything at once after the first overload operator appears? Maybe as a stringstream? Also, I won't be only passing strings, but anything that I need, will this require me to manually create a separate overload function for every signle type that I may pass?
P.S: Cross-plaform solution is optional, but welcome (Currently developing on Linux)
You may return an other class to do the job, something like:
class Helper
{
public:
~Helper() { std::cout << "\n"; }
template<typename T>
friend Helper&& operator << (Helper&&h, const T& t) {
std::cout << t;
return std::move(h);
}
};
class Debug
{
public:
template<typename T>
friend Helper operator<<(Debug&, const T& t)
{
auto tempTime = std::chrono::system_clock::to_time_t(
std::chrono::system_clock::now() );
auto timeString{ctime(&tempTime)};
timeString = timeString.substr(timeString.find(':') - 2, 8);
std::cout << timeString << " >> " << t;
return Helper{};
}
};
Each time you call operator<<, your code prints the time stamp and \n. And that's the problem. To avoid that, you can print the time stamp in the constructor of Debug, and print \n in the destructor.
class Debug {
public:
Debug() {
auto tempTime = std::chrono::system_clock::to_time_t(
std::chrono::system_clock::now() );
std::string timeString(ctime(&tempTime));
timeString = timeString.substr(timeString.find(':') - 2, 8);
std::cout << timeString;
}
~Debug() {
std::cout << "\n";
}
Debug &operator<<(std::string arg_0) {
std::cout << " >> " << arg_0;
return *this;
}
};
In order to debug types other than string, you make operator<< a template:
template <typename T>
Debug &operator<<(T &&arg_0) {
std::cout << " >> " << std::forward<T>(arg_0);
return *this;
}
I see 2 design problems here:
You try to create stream-like object. It means that it doesn't know, when the line ends, until you send EOL to it. Without this information, it doesn't know when to add prefix to "your" line and print it. Consider the two following situation:
DBG << "foo and" << " bar";
and
DBG << "foo and";
... (a lot of code) ...
DBG << " bar";
They look exactly the same inside your Debug class, because:
DBG << "foo and" << " bar"; == (DBG.operator<<("foo and")).operator<<(" bar");
And this is the same as:
DBG.operator<<("foo and");
DBG.operator<<("bar");
So you have to decide how to define the end of the message you want to print (and when do you want to measure the time: At the beginning or at the end of the message?).
When do you want to flush your stream? You have to send std::endl or std::flush to std::cout to flush it. Sending "\n" does not flush std::cout (this is important difference between std::endl and "\n"). If you do not flush it, it may be printed several minutes/hours later (it will wait in a buffer). On the other hand frequent buffer flushing may be a performance killer in application producing large amount of text.
Try to define how your stream should behave when you send to it "\n", std::endl and std::flush (std::endl should be converted to "\n"+std::flush).
About other questions:
I would use simple template to "transfer" parameter of operator<<() to std::cout. It would allow to use your class for any type that can be printed by std::cout. To make things simpler you can define the operator<<() outside your class, eg.:
template<typename tParam>
Debug &operator<<(Debug& stream, tParam const & myParam)
{
...
return stream;
}

Need a macro to create a std::string from a std::ostringstream and a << arg list

I want to write a macro that takes as its only argument a list of std::ostream& operator<< concatenated objects and passes the consolidated string as a single std::string object to a function. The ability to pass the consolidated string to a function is key; in the example below I am aware that the example itself could be rewritten to work simply by defining the macro to ERR_MSG(inputs) std::cout << "ERROR: " << inputs, but sending the output to std::cout is not the goal, it's just the test objective I chose for the example.
I'm using GCC 4.1.2 (Red Hat 4.1.2-52) and upgrading it is not an option. Here's a very boiled-down version of what I've tried:
#include <sstream>
#include <iostream>
#define ERR_MSG(inputs) errMsg(std::ostringstream().str()) // 1
#define ERR_MSG(inputs) errMsg((std::ostringstream()<<inputs).str()) // 2
<aReturnType> errMsg(const std::string& msg) // use with 1 & 2
{
std::cout << "\nERROR: " << msg << "\n\n";
return <someObjectCreatedBasedOnTheInput>;
}
#define ERR_MSG(inputs) errMsg(std::ostringstream()<<inputs) // 3
<aReturnType> errMsg(const std::ostringstream& msg) // use with 3
{
std::cout << "\nERROR: " << msg.str() << "\n\n";
return <someObjectCreatedBasedOnTheInput>;
}
int main()
{
ERR_MSG("A number: " << 24 << ", a char: " << 'c' << ", that's all!");
}
Macro #1 compiles, but of course prints nothing but "" for the message. Neither macros 2 & 3 compile, with the following errors:
#define ERR_MSG(inputs) errMsg((std::ostringstream()<<inputs).str()) // 2
error: ‘struct std::basic_ostream<char, std::char_traits<char> >’ has no member named ‘str’
#define ERR_MSG(inputs) errMsg(std::ostringstream()<<inputs) // 3
no matching function for call to ‘errMsg(std::basic_ostream<char, std::char_traits<char> >&)’
note: candidates are: char* errMsg(const std::string&)
note: char* errMsg(const std::ostringstream&)
I am not interested in how I could rewrite this without macros; I can do that quite easily myself.
=== UPDATE: ===
I forgot to mention that in its real use case, the function called by the macro returns an object that may be used by the caller of the macro. That invalidates any macro implementations that cannot be implemented in a single expression whose result is the returned type of the function called by the macro. The "do nothing" implementation of the macro (for release builds) will simply pass an empty std::string to the function regardless of what the "inputs" are. Sorry for not mentioning that earlier.
Your current problem is that all of the various operator<< functions return an ostream&, not an ostringstream&. You can solve that with a simple cast:
#define ERR_MSG(inputs) errMsg((static_cast<std::ostringstream&>(std::ostringstream().flush() << inputs)).str())
The flush is needed because std::ostringstream() is a temporary. Therefore, you can't call functions on it that take an lvalue reference (ie: std::ostream&). Functions like most operator<< variants. All the flush call does is return the this pointer as an lvalue reference.
If you are willing to use some GCC extension, you could declare an actual ostringstream inside the macro in a block, so that the .str() method can be used without casting:
#define ERR_MSG(inputs) \
do { std::ostringstream _s_; _s_<<inputs;errMsg(_s_.str()); } while(false)
Demo: http://ideone.com/clone/y56lc
Use do { } while (false) idiom to make a few lines macro.
#define ERR_MSG(inputs) \
do { \
std::ostringstream osERR_MSG; \
osERR_MSG << inputs; \
errMsg(osERR_MSG.str()); \
} while (false)
int main() {
if (1) ERR_MSG("A number: " << 24 << ", a char: " << 'c' << ", that's all!");
else return 0;
}
The reason I made such strange name osERR_MSG is to avoid as much as possible cases like this:
int osERR_MSG = 7;
ERR_MSG(osERR_MSG);
#include <sstream>
#include <iostream>
#define ERR_MSG(inputs) errMsg(std::ostringstream().flush()<<inputs)
int errMsg(std::ostream& os)
{
std::ostringstream& oss(static_cast<std::ostringstream&>(os));
const std::string& str(oss.str());
std::cout << "\nERROR: " << str << "\n\n";
return str.length();
}
int main()
{
int i = ERR_MSG("A number: " << 24 << ", a char: " << 'c' << ", that's all!");
std::cout << i << "\n";
}
I'd not create an std::ostringstream but rather have a function called from the destructor of a class derived from std::ostream. Here is an example of this approach:
#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;
}
The example use doesn't use a macro but this can be wrapped easily around the above use of FunctionStream(). Note, that in a macro you probably want to make sure that the type seen by the user of the macro is of type std::ostream& rather than a temporary type so it can be used directly with user defined output operators. To this end you should have an insertion for one of the types directly supported by std::ostream which doesn't have any effect but returns an std::ostream&, for example:
#define SomeMacro(output) FunctionStream(&someFunction) << "" << output
Reinstating Nicol's answer as its the best so far:
Your current problem is that all of the various operator<< functions return an ostream&, not an ostringstream&. You can solve that with a simple cast:
#define ERR_MSG(inputs) errMsg((static_cast<std::ostringstream&>(std::ostringstream().flush() << inputs)).str())
Of course, this still has the problem (like all the answers here) that something like
ERR_MSG(x ? "x is true" : "x is false")
will misbehave in an odd and confusing manner.

print time on each call to std::cout

How would someone do that?
for example I do like:
std::cout << "something";
then it should print the time before "something"
Make your own stream for that :) This should work:
class TimedStream {
public:
template<typename T>
TimedStream& operator<<(const T& t) {
std::cout << getSomeFormattedTimeAsString() << t << std::endl;
return *this;
}
};
TimedStream timed_cout;
void func() {
timed_cout << "123";
}
You'd be able to use this class for every type for which std::cout << obj can be done, so no further work is needed.
But please note that the time will be written before every <<, so you cannot chain them easily. Another solution with explicit timestamp is:
class TimestampDummy {} timestamp;
ostream& operator<<(ostream& o, TimestampDummy& t) {
o << yourFancyFormattedTimestamp();
}
void func() {
cout << timestamp << "123 " << 456 << endl;
}
You could use a simple function that prints the timestamp and then returns the stream for further printing:
std::ostream& tcout() {
// Todo: get a timestamp in the desired format
return std::cout << timestamp << ": ";
}
You would then call this function instead of using std::cout directly, whenever you want a timestamp inserted:
tcout() << "Hello" << std::endl;
ostream& printTimeWithString(ostream& out, const string& value)
{
out << currentTime() << ' ' << value << std::endl;
return out;
}
Generate current time using your favourite Boost.DateTime output format.
This looks like homework. You want something in the line of:
std::cout << time << "something";
Find a way the retrieve the time on your system, using a system call.
Then you'll have to implement a << operator for your system-dependent time class/struct.