Original Question
I am writting a logging class where the goal is to be able to do this:
// thread one Logger() << 'Some string' << std::ios::hex << 45; // thread two Logger() << L'Some wide string' << std::endl;
Currently my Logger header looks something like this:
#pragma once; #include <ostream> class Logger { public: Logger(); ~Logger(); std::ostream* out_stream; }; template <typename T> Logger& operator<< (Logger& logger, T thing) { *logger.out_stream << thing; return logger; }
Some notes about this class:
- Cross platform compatibility is not an issue.
- Inside of Logger.cpp there is a singleton class that takes care of creating the ‘real’ ostream.
- The Logger constructor and deconstructor perform the necessary locking of the singleton.
I have three problems:
- How do I make the operator<< function a friend or member so I can set out_stream as private?
- How do I make the operator<< function work for manipulators?
- How can I add a specialization so that if T is a WCHAR* or std::wstring that it will convert it to char* or std::string before passing it to out_stream? (I can do the conversion. Losing high unicode characters isn’t a problem in my case.)
Summary of things learned in answers:
- Put template BEFORE friend instead of after.
- std::ios::hex is not a manipulator. std::hex is a manipulator.
End Result
#pragma once #include <ostream> #include <string> std::string ConvertWstringToString(std::wstring wstr); class Logger { public: Logger(); ~Logger(); template <typename T> Logger& operator<< (T data) { *out << data; return *this; } Logger& operator<< (std::wstring data) { return *this << ConvertWstringToString(data); } Logger& operator<< (const wchar_t* data) { std::wstring str(data); return *this << str; } private: std::ostream* out; };
You can use friend definition, which will define the operator in the surrounding namespace of the class, and make it only visible to operator overloading resolution (not callable manually using the ::operator<<… syntax):
The alternative, to keep your code as it is and just make the operator<< template a friend, you add this line into your class definition:
For the manipulator problem, i will just give you my code i write some time ago:
};
Note that it is std::hex , but not std::ios::hex. The latter is used as a manipulator flag for the
setffunction of streams. Note that for your example, tho, no special treatment of manipulators is required. The above special treatment of std::endl is only needed because i do stream the time in addition when std::endl is used.