Can I rewrite a logging macro with stream operators to use a C++ template function? - c++

Our project uses a macro to make logging easy and simple in one-line statements, like so:
DEBUG_LOG(TRACE_LOG_LEVEL, "The X value = " << x << ", pointer = " << *x);
The macro translates the 2nd parameter into stringstream arguments, and sends it off to a regular C++ logger. This works great in practice, as it makes multi-parameter logging statements very concise. However, Scott Meyers has said, in Effective C++ 3rd Edition, "You can get all the efficiency of a macro plus all the predictable behavior and type safety of a regular function by using a template for an inline function" (Item 2). I know there are many issues with macro usage in C++ related to predictable behavior, so I'm trying to eliminate as many macros as possible in our code base.
My logging macro is defined similar to:
#define DEBUG_LOG(aLogLevel, aWhat) { \
if (isEnabled(aLogLevel)) { \
std::stringstream outStr; \
outStr<< __FILE__ << "(" << __LINE__ << ") [" << getpid() << "] : " << aWhat; \
logger::log(aLogLevel, outStr.str()); \
}
I've tried several times to rewrite this into something that doesn't use macros, including:
inline void DEBUG_LOG(LogLevel aLogLevel, const std::stringstream& aWhat) {
...
}
And...
template<typename WhatT> inline void DEBUG_LOG(LogLevel aLogLevel, WhatT aWhat) {
... }
To no avail (neither of the above 2 rewrites will compile against our logging code in the 1st example). Any other ideas? Can this be done? Or is it best to just leave it as a macro?

Logging remains one of the few places were you can't completely do away with macros, as you need call-site information (__LINE__, __FILE__, ...) that isn't available otherwise. See also this question.
You can, however, move the logging logic into a seperate function (or object) and provide just the call-site information through a macro. You don't even need a template function for this.
#define DEBUG_LOG(Level, What) \
isEnabled(Level) && scoped_logger(Level, __FILE__, __LINE__).stream() << What
With this, the usage remains the same, which might be a good idea so you don't have to change a load of code. With the &&, you get the same short-curcuit behaviour as you do with your if clause.
Now, the scoped_logger will be a RAII object that will actually log what it gets when it's destroyed, aka in the destructor.
struct scoped_logger
{
scoped_logger(LogLevel level, char const* file, unsigned line)
: _level(level)
{ _ss << file << "(" << line << ") [" << getpid() << "] : "; }
std::stringstream& stream(){ return _ss; }
~scoped_logger(){ logger::log(_level, _ss.str()); }
private:
std::stringstream _ss;
LogLevel _level;
};
Exposing the underlying std::stringstream object saves us the trouble of having to write our own operator<< overloads (which would be silly). The need to actually expose it through a function is important; if the scoped_logger object is a temporary (an rvalue), so is the std::stringstream member and only member overloads of operator<< will be found if we don't somehow transform it to an lvalue (reference). You can read more about this problem here (note that this problem has been fixed in C++11 with rvalue stream inserters). This "transformation" is done by calling a member function that simply returns a normal reference to the stream.
Small live example on Ideone.

No, it is not possible to rewrite this exact macro as a template since you are using operators (<<) in the macro, which can't be passed as a template argument or function argument.
We had the same issue and solved it with a class based approach, using a syntax like
DEBUG_LOG(TRACE_LOG_LEVEL) << "The X value = " << x << ", pointer = " << *x << logger::flush;
This would indeed require to rewrite the code (by using a regular expression) and introduce some class magic, but gives the additional benefit of greater flexibiliy (delayed output, output options per log level (to file or stdout) and things like that).

The problem with converting that particular macro into a function is that things like "The X value = " << x are not valid expressions.
The << operator is left-associative, which means something in the form A << B << C is treated as (A << B) << C. The overloaded insertion operators for iostreams always return a reference to the same stream so you can do more insertions in the same statement. That is, if A is a std::stringstream, since A << B returns A, (A << B) << C; has the same effect as A << B; A << C;.
Now you can pass B << C into a macro just fine. The macro just treats it as a bunch of tokens, and doesn't worry about what they mean until all the substituting is done. At that point, the left-associative rule can kick in. But for any function argument, even if inlined and templated, the compiler needs to figure out what the type of the argument is and how to find its value. If B << C is invalid (because B is neither a stream nor an integer), compiler error. Even if B << C is valid, since function parameters are always evaluated before anything in the invoked function, you'll end up with the behavior A << (B << C), which is not what you want here.
If you're willing to change all the uses of the macro (say, use commas instead of << tokens, or something like #svenihoney's suggestion), there are ways to do something. If not, that macro just can't be treated like a function.
I'd say there's no harm in this macro though, as long as all the programmers who have to use it would understand why on a line starting with DEBUG_LOG, they might see compiler errors relating to std::stringstream and/or logger::log.
If you keep a macro, check out C++ FAQ answers 39.4 and 39.5 for tricks to avoid a few nasty ways macros like this can surprise you.

Related

Why local variable within inline function expanded multiple times in "discrete statements" can have a single set of variables?

I'm reading Inside The C++ Object Model and find confused about inline function expansion.
In general, each local variable within the inline function must be introduced into the enclosing block of the call
as a uniquely named variable. If the inline function is expanded multiple times within one expression, each
expansion is likely to require its own set of the local variables. If the inline function is expanded multiple
times in discrete statements, however, a single set of the local variables can probably be reused across the
multiple expansions.
Here, what does it mean to expand inline function multiple times in discrete statements and how could that happen? Can anyone raise a concrete example to apply this?
I had some trouble to handle the term discrete statement (especially because it has been emphasized multiple times). I tried to find something like a clear definition (by google) but I couldn't. Thus, I decided to read this literally as one statement (with discrete in the sense of separate).
Denoting a function inline is just a hint to the compiler that the programmer would like to have the function body inserted directly at every "call point" (instead of simply calling the function). Actually, the compiler decides whether the function is really inlined. (It might be even inlined at one point of call but become a function call at another point.) If a macro is used instead of the inline function, the inline requirement would be granted (as macro expansion is actually nothing else than text replacement). Of course, macros have a lot of limitations which inline functions have not. One of them is that inline functions may have local variables.
I made a synthetic example. It's not code "ready for production" but it hopefully helps to illustrate the topic:
#include <iostream>
using namespace std;
inline int absValue(int a)
{
int mB = -a;
return a < 0 ? mB : a;
}
int main()
{
int value;
// use input to prevent compile-time computation
cout << "input: " << flush;
cin >> value;
// multiple usages of absValue()
cout << "value: " << value << endl
<< "absValue(value): "
<< absValue(value)
<< endl
<< "absValue(-value): "
<< absValue(-value)
<< endl;
// done
return 0;
}
The second output statement calls function absValue() multiple times where the call should be inlined. I imagine it like:
// multiple usages of absValue()
cout << "value: " << value << endl
<< "absValue(value): "
<< {
int mB = -(value);
return (value) < 0 ? mB : (value);
}
<< endl
<< "absValue(-value): "
<< {
int mB = -(-value);
return (-value) < 0 ? mB : (-value);
}
<< endl;
There are two occurrences of mB in this statement. On one hand, these are two separate local variables. On the other hand, they may share the same storage on stack as they are used consecutively. (They might not share the same storage if the compiler optimization introduces some kind of code re-ordering which results in interleaving of the first and second expansion of absValue().)
This whole explanation is rather theoretically. Practically, the compiler will hopefully put mB into a register or even optimize most of the code away.
I fiddled a little bit with godbolt to illustrate it further. Finally, I must admit that it proofs essentially my last paragraph above.

Easier-to-type alternative to std::cout for printing to screen in C++

Often I just want to quickly check the contents of a series of variables (let's call them a,b,c,d and e, and suppose they're a mixture of floats, integers and strings). I'm fed up typing
cout << a << " " << b << " " << " " << c << " " << " " << d << " " << e << endl;
Is there a more convenient (less key-strokes) way to quickly dump a few variables to stdout in C++? Or do C++ people just always define their own simple print function or something? Obviously something like
printf("%d %f %s %d %s\n",a,b,c,d,e);
is not the alternative I'm looking for, but rather something like
print a,b,c,d,e
Even
print*, a,b,c,d,e
or
write(*,*) a,b,c,d,e
isn't too inconvenient to type.
Of course, googling 'quickly print to screen in C++' keeps just sending me back to std::cout.
Is it that, what you want?
print(a, b, c);
That would be this.
template <typename T>
void print(T t)
{
std::cout << t << " ";
}
template<typename T, typename... Args>
void print(T t, Args... args)
{
std::cout << t << " ";
print(args...) ;
}
It's easy to create a "print" class which have an overloaded template operator,, then you could do something like
print(),a,b,c,d;
The expression print() would create a temporary instance of the print class, and then use that temporary instance for the printing with the comma operator. The temporary instance would be destroyed at the end of the expression (after last comma overload is called).
The implementation could look something like this:
struct print
{
template<typename T>
print& operator,(const T& v)
{
std::cout << v;
return *this;
}
};
Note: This is just off my head, without any testing.
Is there a more convenient (less key-strokes) way to quickly dump a
few variables to stdout in C++?
I would have to say No, not in the language. But I do not consider std::cout a challenging amount to type.
You can tryout the template methods provided by other answer's.
But you should try GDB (or some debugger available on your system). GDB can 'dump' automatic variables with no _effort_ at all, as automatic var's for the current stack frame are always kept up-to-date in the "Locals" window.
Or do C++ people just always define their own simple print function or something?
No, or maybe something.
I use std::cout and std::cerr (as defined) for lots of debugging, but not in the 'how can I save the most typing' frame of mind.
My view is that creating a 'convenience' (i.e. not required) function is appropriate for doing something you wish to repeat. My rule of thumb is 3 times ... if I do a particular something 3 (or more) times (like generate a std::cout statement with the same or similar variables in it) then I might write a function (rather than copy the line) for that repeated effort.
Typically, I use one of two (what I call) disposable debug methods ... and most of my objects also have both show() and dump(), and there can be multiple show/dump functions or methods, each with different signatures, and default values.
if(dbg1) show(a,b,c,d,e);
if(dbg1b) show(b);
// etc
and
if(dbg2) dump(a,b,c,d,e);
Show typically uses and does what what std::cout provides, and little else.
Dump does what show does, but also might provide an alternate view of the data, either hex or binary translations of the values, or perhaps tables. What ever helps.
Disposable does not mean I will dispose of them, but rather I might, and I often get tired of output that does not change, so I set dbgX to false when this code seems to be working, at least until I decide to dispose of the debug invocation.
But then, you do have to implement each of the functions and methods, and yes, you are going to have to learn to type.
If these variables are automatic, you should know that the debugger GDB automatically displays them in a window called "Locals", and keeps them up-to-date during single step.
In GDB, object instance contents can often be displayed with "p *obj", and there are ways to add a particular obj name to the local display window.
It does not take a lot to run GDB. If you object to creating the 80 char std::cout code above, it takes far less typing to launch GDB, set break in main, and run the simple task under gdb control, (then single step to observe these variables at any step in your code) not just where you happened to insert a show() or dump() command.
And if you have GDB, you can also command to print using "p show()" (when the show() function is in scope) to see what the in-scope variables look like to std::cout (if you don't believe the "Locals" window).
GDB allows you to "p this->show()" when stepping through a method of the instance, or "p myObj->show()" when the myObj is accessible.
ALso, "p *this" and "p *myObj" will provide a default, typically useful, display of the current contents your object.
Anyway. Yes you can always work hard to shorten your typing effort.

How to print the name of a variable with parameters?

I would like to print : table_name[variable_value]
by giving ONE input : table_name[variable_name]
Let me explain a simpler case with a toy solution based on a macro:
int i = 1771;
I can print the variable_name with
#define toy_solution(x) cout << #x ;
If I execute
toy_solution(i);
"i" will be printed.
Now, imagine there is a well-allocated table T.
I would like to write in the program:
solution(T[i]);
and to read on the screen "T[1771]".
An ideal solution would treat the two cases, that is :
ideal_solution(i) would print i.
ideal_solution(T[i]) would print T[1771].
It is not important to me to use a macro or a function.
Thanks for your help.
#define toy_solution(x, i) cout << #x << "[" << i << "]"
I would like to print : table_name[variable_value]
by giving ONE input : table_name[variable_name]
well, as you did not understand my comment, I'll say out loud in an answer:
what you want to do is not possible
You have to choose between either #Alin's solution or #lizusek.
I think that #lizusek's solution is better because you're writing C++ code, so if you can do something that gives the same result than with using macros, you should use plain C++ code.
edit: let my try to explain why this is not possible
so what you want is:
f(T[i]) -> T, i
The only way you could write that so it would make sense in preprocessor is:
#define f(T[i]) cout<<#T#<<#i#
but then the preprocessor will give an error, because you can't index an array as a function (even a macro function) parameter:
test.c:5:12: error: expected comma in macro parameter list
#define f(T[i]) cout<<#T#<<#i#
^
If you try to do the same thing using a C++ function, then it's even more non-sense, as a function call such as:
toy_solution(t[i]);
would actually be translated to the value t[i] points to at runtime, so inside the function you'll never be able to known that the given value was actually in an array. So what you want is wrong, and you should stick to good coding practices: using a function and if what you want is:
toy_solution(t[i]);
then use:
toy_solution("t", i);
Possible solutions that you should never use
well, when I say it's not possible, it's that the only solutions I can think off are so twisted that you'd be insane to actually use them in your code… And if you do, I hope I'll never read one of your code or I may become violent :-) That's why I won't show you how or give you any code that could help do what I'm about to tell you.
use a template system
You could either write your code using your own template system or use one commonly used for HTML processing to process your source code through it and apply a transformation rule such as:
toy_solution(t[i]) -> toy_solution("t", t[i])
it's definitely possible, but it makes your build chain even more complicated and dependant on more tools. C/C++ build toolchain are complicated enough, please don't make it worst.
Or you code make your own fork of C and of a C compiler to change the syntax rules so what you want becomes possible. Though, I personnally would never use your fork, and then I'd go trolling and flaming about this on HN, deeply regretting to have given you such a bad idea :-)
use a custom class to encapsulate your arrays in
if you do something like:
template<T>
class Element {
T value;
List<T> _owner;
[…]
}
template<T>
class List {
Element<T> values[];
std::string _name;
[…]
}
so that when you call the function
toy_solution(T[i]);
the implementation would look like:
void toy_solution(Element<T> e) {
std::cout<<e.get_list_name()<<" "<<e.get_value()<<std::endl;
}
but that's sooo much boilerplate and overhead just to avoid doing a simple function definition that does not look as nice as you dream of, that I find it really stupid to do so.
You can write a function as simple as that:
void solution( std::string const& t, int i) {
std::cout << t << "[" << i << "]";
}
usage:
int i = 1771;
solution( "T", i);
You can also write a macro, but be aware that this is not type safe. Function should be preferred.

c++ cout strange behavior with a custom Stack class

I have a custom stack class. Most of the code can be seen here:
Member functions of a templated class, that take a template type as argument
I fill the stack like so:
stack <int> Astack;
Astack.Push(1); Astack.Push(2); Astack.Push(3); Astack.Push(4);
Then I do this:
cout << Astack.Pop() << Astack.Pop() << Astack.Pop() << Astack.Pop() <<endl;
and get this: 1234
However, if I do this:
cout << Astack.Pop(); cout << Astack.Pop(); cout << Astack.Pop(); cout << Astack.Pop();
I get this: 4321, which is obviously what I want.
So, what gives?
The order of evaluation of the function calls is unspecified. Your first expression basically boils down to this:
cout << a << b << c << d;
Each of a, b, c, and d are calls to Astack.Pop(). The compiler can generate code that evaluates those calls in any order it chooses.
You should avoid writing expressions that rely on a particular order of evaluation of parts of the expression. In general, it's not safe (and even when it is safe, it is usually quite confusing).
In the first version the arguments to cout are evaluated from right to left. You never actually specify which order they should be evaluated in, so the one on the right is evaluated first, popping the 4, and so on.
There is something known as Unspecified Behaviour defined by the ISO C++ Standard. Your code-snippet is just an example of that.

Debug-only ostreams in C++?

I've implemented an ostream for debug output which sends ends up sending the debug info to OutputDebugString. A typical use of it looks like this (where debug is an ostream object):
debug << "some error\n";
For release builds, what's the least painful and most performant way to not output these debug statements?
The most common (and certainly most performant) way is to remove them using the preprocessor, using something like this (simplest possible implementation):
#ifdef RELEASE
#define DBOUT( x )
#else
#define DBOUT( x ) x
#endif
You can then say
DBOUT( debug << "some error\n" );
Edit: You can of course make DBOUT a bit more complex:
#define DBOUT( x ) \
debug << x << "\n"
which allows a somewhat nicer syntax:
DBOUT( "Value is " << 42 );
A second alternative is to define DBOUT to be the stream. This means that you must implement some sort of null stream class - see Implementing a no-op std::ostream. However, such a stream does have an runtime overhead in the release build.
A prettier method:
#ifdef _DEBUG
#define DBOUT cout // or any other ostream
#else
#define DBOUT 0 && cout
#endif
DBOUT << "This is a debug build." << endl;
DBOUT << "Some result: " << doSomething() << endl;
As long as you don't do anything weird, functions called and passed to DBOUT won't be called in release builds. This macro works because of operator precedence and the logical AND; because && has lower precedence than <<, release builds compile DBOUT << "a" as 0 && (cout << "a"). The logical AND doesn't evaluate the expression on the right if the expression on the left evaluates to zero or false; because the left-hand expression always evaluates to zero, the right-hand expression is always removed by any compiler worth using except when all optimization is disabled (and even then, obviously unreachable code may still be ignored.)
Here is an example of weird things that will break this macro:
DBOUT << "This is a debug build." << endl, doSomething();
Watch the commas. doSomething() will always be called, regardless of whether or not _DEBUG is defined. This is because the statement is evaluated in release builds as:
(0 && (cout << "This is a debug build." << endl)), doSomething();
// evaluates further to:
false, doSomething();
To use commas with this macro, the comma must be wrapped in parentheses, like so:
DBOUT << "Value of b: " << (a, b) << endl;
Another example:
(DBOUT << "Hello, ") << "World" << endl; // Compiler error on release build
In release builds, this is evaluated as:
(0 && (cout << "Hello, ")) << "World" << endl;
// evaluates further to:
false << "World" << endl;
which causes a compiler error because bool cannot be shifted left by a char pointer unless a custom operator is defined. This syntax also causes additional problems:
(DBOUT << "Result: ") << doSomething() << endl;
// evaluates to:
false << doSomething() << endl;
Just like when the comma was used poorly, doSomething() still gets called, because its result has to be passed to the left-shift operator. (This can only occur when a custom operator is defined that left-shifts a bool by a char pointer; otherwise, a compiler error occurs.)
Do not parenthesize DBOUT << .... If you want to parenthesize a literal integer shift, then parenthesize it, but I'm not aware of a single good reason to parenthesize a stream operator.
How about this? You'd have to check that it actually optimises to nothing in release:
#ifdef NDEBUG
class DebugStream {};
template <typename T>
DebugStream &operator<<(DebugStream &s, T) { return s; }
#else
typedef ostream DebugStream;
#endif
You will have to pass the debug stream object as a DebugStream&, not as an ostream&, since in release builds it isn't one. This is an advantage, since if your debug stream isn't an ostream, that means you don't incur the usual runtime penalty of a null stream that supports the ostream interface (virtual functions that actually get called but do nothing).
Warning: I just made this up, normally I would do something similar to Neil's answer - have a macro meaning "only do this in debug builds", so that it is explicit in the source what is debugging code, and what isn't. Some things I don't actually want to abstract.
Neil's macro also has the property that it absolutely, definitely, doesn't evaluate its arguments in release. In contrast, even with my template inlined, you will find that sometimes:
debug << someFunction() << "\n";
cannot be optimised to nothing, because the compiler doesn't necessarily know that someFunction() has no side-effects. Of course if someFunction() does have side effects then you might want it to be called in release builds, but that's a peculiar mixing of logging and functional code.
Like others have said the most performant way is to use the preprocessor. Normally I avoid the preprocessor, but this is about the only valid use I have found for it bar protecting headers.
Normally I want the ability to turn on any level of tracing in release executables as well as debug executables. Debug executables get a higher default trace level, but the trace level can be set by configuration file or dynamically at runtime.
To this end my macros look like
#define TRACE_ERROR if (Debug::testLevel(Debug::Error)) DebugStream(Debug::Error)
#define TRACE_INFO if (Debug::testLevel(Debug::Info)) DebugStream(Debug::Info)
#define TRACE_LOOP if (Debug::testLevel(Debug::Loop)) DebugStream(Debug::Loop)
#define TRACE_FUNC if (Debug::testLevel(Debug::Func)) DebugStream(Debug::Func)
#define TRACE_DEBUG if (Debug::testLevel(Debug::Debug)) DebugStream(Debug::Debug)
The nice thing about using an if statement is that there is no cost to for tracing that is not output, the tracing code only gets called if it will be printed.
If you don't want a certain level to not appear in release builds use a constant that is available at compile time in the if statement.
#ifdef NDEBUG
const bool Debug::DebugBuild = false;
#else
const bool Debug::DebugBuild = true;
#endif
#define TRACE_DEBUG if (Debug::DebugBuild && Debug::testLevel(Debug::Debug)) DebugStream(Debug::Debug)
This keeps the iostream syntax, but now the compiler will optimise the if statement out of the code, in release builds.
#ifdef RELEASE
#define DBOUT( x )
#else
#define DBOUT( x ) x
#endif
Just use this in the actual ostream operators themselves. You could even write a single operator for it.
template<typename T> Debugstream::operator<<(T&& t) {
DBOUT(ostream << std::forward<T>(t);) // where ostream is the internal stream object or type
}
If your compiler can't optimize out empty functions in release mode, then it's time to get a new compiler.
I did of course use rvalue references and perfect forwarding, and there's no guarantee that you have such a compiler. But, you can surely just use a const ref if your compiler is only C++03 compliant.
#iain: Ran out of room in the comment box so posting it here for clarity.
The use of if statements isn't a bad idea! I know that if statements in macros may have some pitfalls so I'd have to be especially careful constructing them and using them. For example:
if (error) TRACE_DEBUG << "error";
else do_something_for_success();
...would end up executing do_something_for_success() if an error occurs and debug-level trace statements are disabled because the else statement binds with the inner if-statement. However, most coding styles mandate use of curly braces which would solve the problem.
if (error)
{
TRACE_DEBUG << "error";
}
else
{
do_something_for_success();
}
In this code fragment, do_something_for_success() is not erroneously executed if debug-level tracing is disabled.