在c++中输出wstring

利用模板向不同的输出流中以不同的格式输出, 向终端中(std::ostream->std::cout,std::cerr)先窄化为本地编码的std::string交给输出. 对其他的流, 转为 utf-8 输出

此处先给出实现, 等之后在给出具体内容.

头文件

#pragma once
#include <iosfwd>
#if  _HAS_CXX17
#include <string_view>
#else
#include<string>
// hacking
namespace std{
using  wstring_view = const  wstring &;
#endif
namespace encode{
// 将 utf-16 字符串转换为特定 codepage 的多字节字符串存储到 std::string 中
std::string wideToMulti(std::wstring_view sourceStr, unsigned int pagecode);
std::string wideToUtf8(std::wstring_view sourceWStr);
std::string wideToOme(std::wstring_view sourceWStr);
// ostream 特化, 针对 std::cout, std::cerr 等转换为本机 codepage 后以多字节编码输出
// 不能表示的字节会被替换为 '?'
std::ostream &operator<<(std::ostream &os, std::wstring_view str);
// 需要显式转换到 std::wstring_view, 只是一层包装
std::ostream &operator<<(std::ostream &os, const wchar_t *strPt);
// 其他类型的输出流的模板, 输出存储在 std::string 中的 utf-8 字符串
template <typename Ostream>
Ostream &operator<<(Ostream &os, std::wstring_view str)
    os << encode::wideToUtf8(str);
    return os;
template <typename Ostream>
Ostream &operator<<(Ostream &os, const wchar_t *strPt)
    return os << std::wstring_view(strPt);

实现

#include "head.h"
#include <windows.h>
#include <iostream>
namespace encode
    std::string wideToMulti(std::wstring_view sourceStr, UINT pagecode)
        auto newLen = WideCharToMultiByte(pagecode, 0, sourceStr.data(), sourceStr.size(), 
                                           nullptr, 0, nullptr, nullptr);
        std::string targetStr;
        targetStr.resize(newLen);
        WideCharToMultiByte(pagecode, 0, sourceStr.data(), sourceStr.size(), 
                             &targetStr[0], targetStr.size(), nullptr, nullptr);
        return targetStr;
    std::string wideToUtf8(std::wstring_view sourceWStr)
        return wideToMulti(sourceWStr, 65001);
    std::string wideToOme(std::wstring_view sourceWStr)
        return wideToMulti(sourceWStr, CP_OEMCP);
std::ostream &operator<<(std::ostream &os, const wchar_t *strPt)
    return os << std::wstring_view(strPt);
std::ostream &operator<<(std::ostream &os, std::wstring_view str)
    return os << encode::wideToOme(str);
// 一个不合规的实现, 直接将 wstring 写入 stdout 避免字符窄化带来的乱码
// std::ostream &operator<<(std::ostream &os, std::wstring_view str)
//     auto static outHd = GetStdHandle(STD_OUTPUT_HANDLE);
//     WriteConsoleW(outHd,str.data(),str.size(),nullptr,NULL);
//     return os;
// }

这里对 ostream 的重载有两个实现, 一个是窄化之后通过输出; 另一个是通过 winapi 直接输出, 这样会跳过 ostream 本身, 但不会因为窄化而损失信息.

//示例 
#include"head.h"
#include<iostream>