Home > Back-end >  Function to print data type to debug console
Function to print data type to debug console

Time:08-12

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());
}

Online Demo

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());
}

Online Demo

  • Related