如何为已定义的函数类型添加noexcept说明符?
解决方案
你遇到的核心问题是原有模板特化仅支持默认调用约定的函数类型,无法匹配带自定义调用约定(比如你用的WINAPI即MSVC下的__stdcall)的函数类型,所以会丢失调用约定信息。另外属性保留受限于C++标准规则,有明确的边界。
1. 补全调用约定特化
针对你用到的调用约定补充对应的模板特化即可保留调用约定信息,以下是适配MSVC环境WINAPI的完整实现:
#include <type_traits> template<typename> struct noexcept_trait; // 默认cdecl调用约定 非noexcept版本 template<typename Result, typename... Args> struct noexcept_trait<Result(Args...)> { using as_noexcept = Result(Args...) noexcept; using as_throwing = Result(Args...); }; // 默认cdecl调用约定 noexcept版本 template<typename Result, typename... Args> struct noexcept_trait<Result(Args...) noexcept> { using as_noexcept = Result(Args...) noexcept; using as_throwing = Result(Args...); }; // __stdcall调用约定(WINAPI)非noexcept版本 template<typename Result, typename... Args> struct noexcept_trait<Result __stdcall(Args...)> { using as_noexcept = Result __stdcall(Args...) noexcept; using as_throwing = Result __stdcall(Args...); }; // __stdcall调用约定(WINAPI)noexcept版本 template<typename Result, typename... Args> struct noexcept_trait<Result __stdcall(Args...) noexcept> { using as_noexcept = Result __stdcall(Args...) noexcept; using as_throwing = Result __stdcall(Args...); }; // 可选:补充其他用到的调用约定特化,比如__cdecl、__fastcall、__vectorcall等,格式同上 template<typename T> using add_noexcept_t = typename noexcept_trait<T>::as_noexcept; template<typename T> using remove_noexcept_t = typename noexcept_trait<T>::as_throwing; // 适配你要求的as_noexcept<T>::type写法 template<typename T> struct as_noexcept { using type = add_noexcept_t<T>; };
2. 测试验证
你原来的测试代码可以直接正常运行,调用约定会完整保留:
typedef DWORD WINAPI HANDLER_FUNCTION_EX (DWORD); static as_noexcept<HANDLER_FUNCTION_EX>::type my_func; // 前置声明 static_assert(noexcept(my_func(0))); // 断言通过
3. 关于属性保留的说明
[[deprecated]]这类标准属性不属于C类型系统的一部分,无法通过类型转换自动继承,这是C标准的固有规则,无法通过模板实现绕过。如果需要给函数加属性,直接在最终的函数声明处手动添加即可。
如果需要跨编译器兼容,可以用宏包裹调用约定特化部分,避免不同编译器下调用约定关键字不识别的编译错误。
内容的提问来源于stack exchange,提问作者OwnageIsMagic
相关产品推荐
相关产品推荐

