如何在编译期推导模板参数中可调用对象的返回类型?
如何让函数包装器自动推导返回类型?
我有一个用于包装自由函数(如open()、close())的模板,代码如下:
template <auto fn, typename ReturnType=void> struct func_wrapper { template<typename... Args> constexpr ReturnType operator()(Args&&... args) const { if constexpr( std::is_same<ReturnType, void>::value) { fn(std::forward<Args>(args)...); } else { return fn(std::forward<Args>(args)...); } } };
使用时需要手动指定返回类型:
void CloseFunc2(int a); int OpenFunc2(const std::string&, int flags); using FileWrapper2 = DevFileWrapper<func_wrapper<OpenFunc2, int>, func_wrapper<CloseFunc2>>;
代码能正常运行,但我希望创建func_wrapper时无需手动指定ReturnType。尝试用std::invoke_result推导返回类型但失败,错误代码如下:
template<typename... Args> constexpr auto operator()(Args&&... args) const -> std::invoke_result<fn(std::forward<Args>(args)...)>::type { if constexpr( std::is_same<ReturnType, void>::value) { fn(std::forward<Args>(args)...); } else { return fn(std::forward<Args>(args)...); } }
编译报错:
template-parameter-callable.cpp:48:71: error: template argument for template type parameter must be a type constexpr auto operator()(Args&&... args) const -> std::invoke_result<fn(std::forward<Args>(args)...)>::type { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/ usr/include/c++/v1/type_traits:4009:17: note: template parameter is declared here template <class _Fn, class... _Args> ^ 1 error generated.
解决方案
错误原因
std::invoke_result的模板参数使用错误:它需要传入可调用对象的类型(如decltype(fn))和参数类型列表,而非直接传入函数调用表达式fn(...)。
优化后的包装器
直接利用C++14的auto返回类型推导,去掉冗余的ReturnType模板参数,让编译器自动推导返回值:
#include <type_traits> #include <utility> template <auto fn> struct func_wrapper { template<typename... Args> constexpr auto operator()(Args&&... args) const { // 用decltype推导调用fn后的返回类型,判断是否为void if constexpr(std::is_void_v<decltype(fn(std::forward<Args>(args)...))>) { fn(std::forward<Args>(args)...); } else { return fn(std::forward<Args>(args)...); } } };
使用方式
现在无需手动指定返回类型,直接传入函数即可:
void CloseFunc2(int a); int OpenFunc2(const std::string&, int flags); // 编译器自动推导返回类型 using FileWrapper2 = DevFileWrapper<func_wrapper<OpenFunc2>, func_wrapper<CloseFunc2>>;
内容的提问来源于stack exchange,提问作者mark
相关产品推荐
相关产品推荐

