在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>