On May 22, 2008, at 6:21 PM, Dale King wrote:
I'm going to file a bug on what I consider a major problem with wide versus normal character strings and the << operator to append to the MessageBuffer. The problem is that the first thing in your message determines the behavior of the rest of the message.
That is by design.
If the first thing you output is not a wide string, then any other character strings that are wide will be treated as just the pointer value.
That is a side effect of the compiler casting the wchar_t* to int for us. If the L"2"
Consider these statements on a platform (i.e. Windows) where WCHAR is used with various combinations of wide and normal strings: LOG4CXX_TRACE( logger, L"1" << L"2" ); LOG4CXX_TRACE( logger, "1" << L"2" ); LOG4CXX_TRACE( logger, L"1" << "2" ); LOG4CXX_TRACE( logger, 1 << "2" ); LOG4CXX_TRACE( logger, 1 << L"2" ); The expected result is 5 logging events all with the message "12". Instead I get: 12 1006E1C4C 12 12 1006E1C4C Most of the << operators in the MessageBuffer class return either CharMessageBuffer & or std::ostream &. I think all of these should probably be returning MessageBuffer which would allow it to switch to a WideMessageBuffer if I ever add a wide string, not just if the first string is wide.
The idea of the whole MessageBuffer family was support for std::basic_string<char> insertion behavior that the log4cxx 0.9.7 offered while eliminating the surprisingly expensive (at least for some STL implementations) std::basic_ostream<char> constructor when you were just logging a single char* and working right when logging wchar_t strings. The last had more flexibility since there wasn't a released code base with which we had to be compatible. Getting that to work and working across multiple compilers was to say the least a challenge.
As far as I can tell, the behavior you are observing is the same as you would get with log4cxx 0.9.7, even if it was not what you would expect.
If instead of
LOG4CXX_TRACE( logger, "1" << L"2" );
you had done
LOG4CXX_TRACE( logger, "1" << std::wstring(L"2") );
you would have gotten a compile error (at least with gcc on Mac OS/ X). That is because the compiler won't quietly cast a std::wstring to an int like it does a wchar_t*. If the first works, then the second should also be supported.
Things would really start getting hugely complicated if you started inserting objects where one might only have a std::basic_ostream<char> insertion operator and another might only have a std::basic_ostream<wchar_t> operator. Then throw in manipulators and things just spiral out of control trying to do it perfect.
I'd be leaning toward adding private insertion operations to result in a compiler error when you mismatch string types on a logging call. That might result in some code that compiled in log4cxx 0.9.7 to fail to compile (code that expected the pointer value to be output), but that seems like an improvement to break that code.