Win32 SQL ODBC API封装:基于输入类型选A/W版函数的模板问题
自动匹配Win32 ODBC API的ANSI/宽字符版本函数
我懂你在封装Win32 ODBC API时碰到的这个麻烦——一堆成对的GetXXXTextA和GetXXXTextW函数,每次都要手动区分调用版本实在太繁琐,想让代码根据传入的字符类型自动选对应的A/W实现对吧?你已经用模板和std::enable_if迈出了第一步,我给你补全一个完整且实用的方案:
第一步:定义类型限制模板
先完善你写的类型校验模板,确保模板参数只能是char或wchar_t,避免传入其他类型导致编译错误:
#include <type_traits> template<typename T> struct only_char_or_wchar_t { // 仅当T是char或wchar_t时,才会生成有效类型 using type = std::enable_if_t<std::is_same_v<T, char> || std::is_same_v<T, wchar_t>, T>; }; // 模拟ODBC的A/W测试函数 int _stdcall pruebaA(int, char*, const char*) { return 0; } int _stdcall pruebaW(int, wchar_t*, const wchar_t*) { return 0; }
第二步:实现自动匹配的模板调用器
这里有两种主流实现方式,你可以根据C++版本选择:
方式1:模板特化(兼容C++11及以上)
通过模板特化,为char和wchar_t分别绑定对应的A/W函数:
// 主模板,仅声明不实现,限制只能实例化char/wchar_t版本 template<typename T, typename = typename only_char_or_wchar_t<T>::type> int call_prueba(int param1, T* buf, const T* src); // char类型特化,调用pruebaA template<> int call_prueba<char>(int param1, char* buf, const char* src) { return pruebaA(param1, buf, src); } // wchar_t类型特化,调用pruebaW template<> int call_prueba<wchar_t>(int param1, wchar_t* buf, const wchar_t* src) { return pruebaW(param1, buf, src); }
方式2:if constexpr(C++17及以上更简洁)
利用C++17的if constexpr编译期分支,不用写重复的特化代码:
template<typename T, typename = typename only_char_or_wchar_t<T>::type> int call_prueba(int param1, T* buf, const T* src) { if constexpr (std::is_same_v<T, char>) { return pruebaA(param1, buf, src); } else if constexpr (std::is_same_v<T, wchar_t>) { return pruebaW(param1, buf, src); } // 因为有类型限制,这里永远不会走到 }
使用示例
现在调用的时候完全不用手动指定A/W,编译器会自动根据传入的字符类型匹配:
// 自动调用pruebaA char c_buf[256]; call_prueba(123, c_buf, "test"); // 自动调用pruebaW wchar_t w_buf[256]; call_prueba(123, w_buf, L"test");
批量处理优化:用宏简化重复代码
如果要封装大量ODBC的A/W函数对,写重复的特化代码太麻烦,可以用宏来一键生成调用器:
#define DEFINE_AW_CALLER(func_name) \ template<typename T, typename = typename only_char_or_wchar_t<T>::type> \ int call_##func_name(int param1, T* buf, const T* src); \ template<> \ int call_##func_name<char>(int param1, char* buf, const char* src) { \ return func_name##A(param1, buf, src); \ } \ template<> \ int call_##func_name<wchar_t>(int param1, wchar_t* buf, const wchar_t* src) { \ return func_name##W(param1, buf, src); \ } // 一行宏定义,生成prueba的自动调用器 DEFINE_AW_CALLER(prueba) // 后续新增其他函数对,比如GetColumnNameText,直接加一行: // DEFINE_AW_CALLER(GetColumnNameText)
这样你的封装库就能优雅地处理ANSI和宽字符版本的切换,用户使用起来也更直观。
内容的提问来源于stack exchange,提问作者yo_gdg
相关产品推荐
相关产品推荐

