While searching for any kind of function in could help printing data to debug console, I've found this function here on StackOverflow
that can print almost any kind of data:
template <typename Arg, typename... Args>
void doPrint(Arg&& arg, Args&&... args)
{
std::stringstream out;
out << std::forward<Arg>(arg);
using expander = int[];
(void)expander {
0, (void(out << std::left << std::setw(20) << std::forward<Args>(args)), 0)...
};
OutputDebugStringA(out.str().c_str());
}
But it doesn't work when I try to pass a wstring
to it, ex:
std::wstring color = L"blue";
doPrint("color: ", color);
I get this error:
Error C2679 binary '<<': no operator found which takes a right-hand operand of type 'std::wstring' (or there is no acceptable conversion)
Is it possible to also support wstring
?
I tried to change std::stringstream
to std::wstringstream
, but now I get error on OutputDebugStringA()
:
void OutputDebugStringA(LPCSTR)': cannot convert argument 1 from 'std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>' to 'LPCSTR'
CodePudding user response:
By default, you can't print a std::wstring
to a char
-based std::ostream
, such as std::stringstream
, because std::basic_ostream<char>
(aka std::ostream
) does not have an overloaded operator<<
defined for std::wstring
(or const wchar_t*
).
You could define your own operator<<
for that purpose, which converts a std::wstring
to a std::string
/char*
using WideCharToMultiByte()
or equivalent conversion, and then print that instead, eg:
std::ostream& operator<<(std::ostream &os, const std::wstring &wstr)
{
int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), nullptr, 0, nullptr, nullptr);
if (len > 0) {
std::string str;
str.resize(len);
WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), str.data()/* or: &str[0] */, len, nullptr, nullptr);
os << str;
}
return os;
}
template <typename Arg, typename... Args>
void doPrint(Arg&& arg, Args&&... args)
{
std::stringstream out;
out << std::forward<Arg>(arg);
using expander = int[];
(void)expander {
0, (void(out << std::left << std::setw(20) << std::forward<Args>(args)), 0)...
};
OutputDebugStringA(out.str().c_str());
}
Otherwise, you need a wchar_t
-based std::basic_ostream<wchar_t>
(aka std::wostream
) instead, such as std::wstringstream
, using OutputDebugStringW()
for the logging (unless you convert the output std::wstring
to std::string
to log with OutputDebugStringA()
). Fortunately, std::basic_ostream<CharT>
does have an overloaded operator<<
for const char*
strings (but not std::string
) regardless of whether CharT
is char
or wchar_t
, so std::wstringstream
can print the pointer returned by std::string::c_str()
, eg:
std::wostream& operator<<(std::wostream &os, const std::string &str)
{
os << str.c_str();
return os;
}
template <typename Arg, typename... Args>
void doPrint(Arg&& arg, Args&&... args)
{
std::wostringstream out;
out << std::forward<Arg>(arg);
using expander = int[];
(void)expander {
0, (void(out << std::left << std::setw(20) << std::forward<Args>(args)), 0)...
};
OutputDebugStringW(out.str().c_str());
}