What I'm doing is just to insert char and convert them to wide or narrow char. The conversion is performed at compile time, and if you use only characters that are equal in wide and narrow coding, it works. This is tiring, but it really works.
template <typename charT, typename traits> std::basic_ostream<charT, traits>& operator<<( std::basic_ostream<charT, traits>& lhs, const Process& rhs ) { lhs << charT('P') << charT('r') << charT('o') << charT('c') << charT('e') << charT('s') << charT('s') << charT(' ') << charT('(') << charT('0') << charT('x') << std::setw(8) << std::hex << std::setfill(charT('0')) << rhs.GetId() << charT(')') << charT(' '); lhs << rhs.GetName() << std::endl; lhs << charT('C') << charT('o') << charT('m') << charT('m') << charT('a') << charT('n') << charT('d') << charT(' ') << charT('L') << charT('i') << charT('n') << charT('e') << charT(':') << charT(' ') << rhs.GetCmdLine() << std::endl; const std::vector<Thread>& threads = rhs.GetThreads(); for (std::vector<Thread>::const_iterator it = threads.begin(); it != threads.end(); ++it) { lhs << charT(' ') << charT('-') << charT('-') << charT('>') << charT(' ') << *it << std::endl; } const std::map<void *, Module>& modules = rhs.GetModules(); for (std::map<void *, Module>::const_iterator it = modules.begin(); it != modules.end(); ++it) { lhs << charT(' ') << charT('-') << charT('-') << charT('>') << charT(' ') << it->second << std::endl; } return lhs; }
If you have many lines, you can use another template that you will specialize in wide or narrow type of characters and use to store strings. This, however, will force you to duplicate your lines (and you violate the DRY principle).
template <typename charT> struct ProcessInsertionOperatorHelper { static const charT* const String1; static const charT* const String2; static const charT* const String3; static const charT* const String4; }; template <> const wchar_t* const ProcessInsertionOperatorHelper<wchar_t>::String1 = L"Process (0x"; template <> const wchar_t* const ProcessInsertionOperatorHelper<wchar_t>::String2 = L") "; template <> const wchar_t* const ProcessInsertionOperatorHelper<wchar_t>::String3 = L"Command Line: "; template <> const wchar_t* const ProcessInsertionOperatorHelper<wchar_t>::String4 = L" --> "; template <> struct ProcessInsertionOperatorHelper<char> { }; template <typename charT, typename traits> std::basic_ostream<charT, traits>& operator<<( std::basic_ostream<charT, traits>& lhs, const Process& rhs ) { lhs << ProcessInsertionOperatorHelper<charT>::String1 << std::setw(8) << std::hex << std::setfill(L'0') << rhs.GetId() << ProcessInsertionOperatorHelper<charT>::String2; lhs << rhs.GetName() << std::endl; lhs << ProcessInsertionOperatorHelper<charT>::String3 << rhs.GetCmdLine() << std::endl; const std::vector<Thread>& threads = rhs.GetThreads(); for (std::vector<Thread>::const_iterator it = threads.begin(); it != threads.end(); ++it) { lhs << ProcessInsertionOperatorHelper<charT>::String4 << *it << std::endl; } const std::map<void *, Module>& modules = rhs.GetModules(); for (std::map<void *, Module>::const_iterator it = modules.begin(); it != modules.end(); ++it) { lhs << ProcessInsertionOperatorHelper<charT>::String4 << it->second << std::endl; } return lhs; }
source share