How to overload the ostream operator << to make it work with log4cxx in C++?
Asked Answered
I

3

10

Say I have a class A and an operator<< declared like so:

// A.h
class A
{
    // A stuff
};
std::ostream& operator<<(std::ostream& os, const A& a);

somewhere else I use my logger with A:

LoggerPtr logger(LogManager::getLogger("ThisObject"));
A a;
LOG4CXX_INFO(logger, "A: " << a);

The compiler is complaining: binary '<<' : no operator found which takes a right-hand operand of type 'const A' (or there is no acceptable conversion) D:\dev\cpp\lib\apache-log4cxx\log4cxx\include\log4cxx\helpers\messagebuffer.h 190

This error takes me to the declaration of the operator<<:

// messagebuffer.h
template<class V>
std::basic_ostream<char>& operator<<(CharMessageBuffer& os, const V& val) {
    return ((std::basic_ostream<char>&) os) << val;
}

LOG4XX_INFO macro expands to:

#define LOG4CXX_INFO(logger, message) { \
    if (logger->isInfoEnabled()) {\
       ::log4cxx::helpers::MessageBuffer oss_; \
       logger->forcedLog(::log4cxx::Level::getInfo(), oss_.str(oss_ << message), LOG4CXX_LOCATION); }}

MessageBuffer "defines" this operator as well:

// messagebuffer.h
template<class V>
std::ostream& operator<<(MessageBuffer& os, const V& val) {
    return ((std::ostream&) os) << val;
}

I don't understand how to overload this operator the right way to make it work. Any idea?

Inge answered 13/5, 2011 at 10:58 Comment(5)
@Alan Stokes: I am using Visual Studio 2010Inge
Try to include A.h before messagebuffer.hKleon
@Juraj Blaho: Why do you think it would? At the time the compiler performs its lookup, my operator is perfectly defined and known.Inge
@mister why: The error message suggests it is not known/visible.Kleon
@Juraj Blaho: Indeed it does, but I think it's related to the fact the error is pointing to a peculiar operator<< that takes a CharMessageBuffer instead of an ostream. I don't want to introduce a log4cxx implementation dependency in my class.Inge
H
7

You could try declaring your operator << in namespace std (that's legal, since you're passing an instance of your user-defined type):

namespace std {
   ostream& operator<<(ostream& os, const A& a);
}
Hugibert answered 13/5, 2011 at 13:45 Comment(4)
I am not used to polute a namespace that's not mine but I should admit that worked like a charm! Cheers.Inge
I'm interested in understanding why the compiler cannot find my operator in this context.Inge
So am I! I think ADL (argument dependent lookup) should make your code just work; but ADL is full of subtleties, and Visual Studio adds its own idiosyncrasies. The namespace std trick has worked for me before. It's not as bad as it looks, once you get used to it.Hugibert
ADL is only taken into account, if the there are no matches in the nearest enclosing namespace. I learned a lot about this when reading this.Frizzy
M
2

Alan's suggestion of putting the user-defined operator in the std namespace works. But I prefer putting the user-defined operator in the log4cxx::helpers namespace, which also works. Specifically,

namespace log4cxx { namespace helpers {
    ostream& operator<<(ostream& os, const A& a);
} }
Mccrory answered 10/1, 2014 at 4:42 Comment(0)
S
0

I don't have a compiler available right now but i think the problem is caused by trying to use insert operator on a constant string. "A: " << a

Sayres answered 13/5, 2011 at 12:15 Comment(1)
I am not inserting in a constant string; you must have misread the LOG4CXX_INFO expansion.Inge

© 2022 - 2024 — McMap. All rights reserved.