当TCHAR为char或wchar_t时,如何向std::ostream输出TCHAR字符串?
问题解决:兼容TCHAR两种类型的std::ostream输出方案
问题背景
同一个命令行解析源文件被编译到不同可执行文件中,其中一个exe的TCHAR为char,另一个为wchar_t。新增的共享库路径输出功能在前者中正常,后者却输出地址而非路径——原因是std::ostream对const char*有重载输出字符串,对const wchar_t*无对应重载,会匹配到const void*重载输出地址。
尝试用C++17的if constexpr分支处理:当TCHAR为char时直接输出路径,为wchar_t时转成char再输出,但编译失败,错误如下:
1>...\CliContext.cpp(1703,81): error C2664: 'errno_t wcstombs_s(size_t *,char *,size_t,const wchar_t *,size_t)': cannot convert argument 4 from 'char [260]' to 'const wchar_t *' 1>...\CliContext.cpp(1703,55): message : Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\ucrt\stdlib.h(999,26): message : see declaration of 'wcstombs_s'
错误原因
原代码中用sizeof(*me32.szExePath)作为if constexpr的判断条件,但me32是运行时局部变量,该表达式并非编译期常量,导致if constexpr无法在编译期剔除不匹配的分支,两个分支都会被编译。当TCHAR为char时,第二个分支里的me32.szExePath是char数组,与wcstombs_s要求的const wchar_t*参数类型冲突,引发编译错误。
解决方案
改用编译期可确定的TCHAR类型判断,结合std::is_same_v(需包含<type_traits>头文件),确保if constexpr能正确在编译期丢弃无效分支。同时增加跨平台兼容性处理:
修正后的代码
#include <windows.h> #include <tlhelp32.h> #include <tchar.h> #include <type_traits> #include <iostream> #include <memory> #include <cassert> static void sharedLibraries(std::ostream& os) { #ifdef _WIN32 auto dwPID = GetCurrentProcessId(); HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID); if (hModuleSnap == INVALID_HANDLE_VALUE) { std::cerr << "CreateToolhelp32Snapshot (of modules) failed" << std::endl; return; } using Handle_uptr = std::unique_ptr<void, decltype(&CloseHandle)>; Handle_uptr h(hModuleSnap, &CloseHandle); MODULEENTRY32 me32; me32.dwSize = sizeof(me32); if (!Module32First(hModuleSnap, &me32)) { std::cerr << "Module32First failed" << std::endl; return; } do { assert(me32.th32ProcessID == dwPID); if constexpr (std::is_same_v<TCHAR, char>) { os << me32.szExePath << std::endl; } else if constexpr (std::is_same_v<TCHAR, wchar_t>) { size_t size = 0; char path[MAX_PATH * 4]; wcstombs_s(&size, path, sizeof(path), me32.szExePath, sizeof(path) - 1); os << path << std::endl; } } while (Module32Next(hModuleSnap, &me32)); #else os << "Shared library listing is not supported on non-Windows platforms" << std::endl; #endif }
关键修正点
- 编译期类型判断:用
std::is_same_v<TCHAR, char>和std::is_same_v<TCHAR, wchar_t>作为if constexpr的条件,这是编译期可确定的常量表达式,确保无效分支被完全剔除。 - 头文件依赖:添加
<type_traits>头文件,否则std::is_same_v无法使用。 - 跨平台处理:用
_WIN32宏包裹Windows平台专属代码,保证跨平台编译时不会出现未定义符号。 - 错误处理增强:替换原自定义
raise为标准流输出错误信息,提升代码健壮性。
验证说明
- 当
TCHAR为char时,wchar_t分支的代码会在编译期被完全忽略,不会触发类型转换错误。 - 当
TCHAR为wchar_t时,wcstombs_s会将宽字符串转换为多字节字符串,适配std::ostream的输出要求。
内容的提问来源于stack exchange,提问作者ddevienne
相关产品推荐
相关产品推荐

