I am trying to wrap a #define macro in C++ into an inline or template function. In LOG4CXX it has a define such as:
#define LOG4CXX_INFO(logger, message) { \
if (logger->isInfoEnabled()) {\
::log4cxx::helpers::MessageBuffer oss_; \
logger->forcedLog(::log4cxx::Level::getInfo(), oss_.str(oss_ << message), LOG4CXX_LOCATION); }}
I am needing to add other context to the logs and have wrapped LOG4CXX_INFO in another define and have this implementation working. I am wanting to move away from using a #define to wrap this and do it in a more C++ way. This issue I am running into is that the message param can be of various types of objects concated together using + or << operators and this is currently handled in the MessageBuffer class with operator overrides.
If I try to template it such as:
template<typename T>
void info(LoggerPtr logger, const T& message) {
...do stuff ...
LOG4CXX_INFO(logger, message);
}
The compiler will complain about not finding << operators for various types of objects.
What needs to be done to make this work?
Compiled with the following on ubuntu
gcc main.cpp -lstdc++ -llog4cxx
#include <log4cxx/logger.h>
using namespace std;
#define info(logger, message) LOG4CXX_INFO(logger, message)
template<typename T> void tinfo(log4cxx::LoggerPtr logger, const T& message) {
LOG4CXX_INFO(logger, message);
}
int main()
{
log4cxx::LoggerPtr logger;
LOG4CXX_INFO(logger, "test" << "test2");
info(logger,"another test");
info(logger,"another test" << "another test2");
tinfo(logger,"test template");
//tinfo(logger,"test template" << "test template 2"); -> this line does not compile
return 0;
}
Compiler error:
main.cpp: In function ‘int main()’:
main.cpp:21:31: error: invalid operands of types ‘const char [14]’ and ‘const char [16]’ to binary ‘operator<<’
tinfo(logger,"test template" << "test template 2");
MessageBuffer code can be found here: https://github.com/apache/logging-log4cxx/blob/master/src/main/include/log4cxx/helpers/messagebuffer.h and here https://github.com/apache/logging-log4cxx/blob/master/src/main/cpp/messagebuffer.cpp
is wrong. It first evaluates
"test template" << "test template 2"and then passes the result to the function. But that makes no sense, since the left-hand side of<<should be a stream object.This works with the macro, because macros are pure text substitution, so the substitution
yields
which is evaluated left-to-right. If you add parentheses around the macro argument
you reproduce the function behavior faithfully and you will get the same error because you would be evaluating
If you want to output multiple things in one function call I suggest using a fold expression (available since C++17):
If you want to keep the original syntax and/or refer to
LOG4CXX_INFOinstead of reimplementing the body of that macro, then I don't think it is possible without macros.