如何判断模板参数是否为NULL并避免打印时抛出异常?
问题
我使用如下模板向控制台打印不同类型的数据,但当参数为NULL时会抛出异常。我尝试添加了检查参数个数的代码:
if (sizeof...(args) == 0) return;
但仍无法处理NULL值。
当前使用的模板代码:
template <typename Arg, typename... Args> void doPrint(Arg&& arg, Args&&... args) { if (sizeof...(args) == 0) return; 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)... }; OutputDebugString(out.str().c_str()); std::cout << out.str().c_str() << std::endl; }
异常复现代码:
BSTR name = NULL; doPrint("name: ", name);
解决方案
核心是对每个输出参数做NULL校验,针对指针类型(尤其是BSTR这类宽字符指针)替换为友好的占位文本,避免直接输出NULL导致异常。
1. 编写NULL校验辅助函数
实现重载的辅助函数,专门处理可能为NULL的指针类型:
// 默认情况:非指针类型直接返回原参数 template <typename T> auto handleNull(T&& val) -> decltype(std::forward<T>(val)) { return std::forward<T>(val); } // 处理BSTR类型的NULL inline const wchar_t* handleNull(BSTR val) { return val ? val : L"<NULL>"; } // 扩展处理宽字符串指针的NULL inline const wchar_t* handleNull(const wchar_t* val) { return val ? val : L"<NULL>"; } // 扩展处理窄字符串指针的NULL inline const char* handleNull(const char* val) { return val ? val : "<NULL>"; }
这个函数会自动匹配参数类型,为NULL的指针返回对应的占位字符串,其他类型原样返回。
2. 修改doPrint模板调用辅助函数
将原模板中所有输出参数的位置替换为调用handleNull的结果,同时修正宽字符串输出的问题:
template <typename Arg, typename... Args> void doPrint(Arg&& arg, Args&&... args) { std::wostringstream out; // 第一个参数也做NULL校验 out << handleNull(std::forward<Arg>(arg)); using expander = int[]; (void)expander { 0, (void(out << std::left << std::setw(20) << handleNull(std::forward<Args>(args))), 0)... }; OutputDebugString(out.str().c_str()); std::wcout << out.str() << std::endl; }
注:原代码中用std::cout输出宽字符串可能出现乱码,改成std::wcout更适配wostringstream的宽字符输出。
额外优化
原代码中if (sizeof...(args) == 0) return;可以移除,这样模板也支持单参数打印;如果需要保留无参数时直接返回的逻辑,可以保留,但要注意单参数场景的兼容性。
内容的提问来源于stack exchange,提问作者Cesar
相关产品推荐
相关产品推荐

