C++模板调用重载静态成员函数时无法推导模板参数的问题
模板函数调用重载静态成员函数编译失败的问题解析
问题场景
编写了一个通用模板函数dosomething,用于包装对象方法或类静态成员的调用,意图添加异常处理等通用逻辑,但调用重载的静态成员函数时编译报错。
示例代码
#include <iostream> #include <string> #include <functional> class Helper { public: static std::string getSomething() { return "None"; } static std::string getSomething(const std::string& ref) { return ref; } }; template <typename Func, typename... Args> inline std::invoke_result_t<Func, Args...> dosomething(Func&& f, Args&&... args) { if constexpr (sizeof...(Args) == 0) return std::invoke(std::forward<Func>(f)); else return std::invoke(std::forward<Func>(f), std::forward<Args>(args)...); } int main() { std::cout << "Invoke " << dosomething(&Helper::getSomething, "test"); std::cout << "Invoke " << dosomething(&Helper::getSomething); }
编译错误信息
>------ Build started: Project: Template_TEst, Configuration: Debug Win32 ------ Template_TEst.cpp Template_TEst.cpp(41,31): error C2672: 'dosomething': no matching overloaded function found Template_TEst.cpp(41,31): error C2783: '_Select_invoke_traits<_Callable,_Args...>::type dosomething(Func &&,Args &&...)': could not deduce template argument for 'Func' Template_TEst.cpp(26): message : see declaration of 'dosomething' Template_TEst.cpp(42,31): error C2672: 'dosomething': no matching overloaded function found Template_TEst.cpp(42,31): error C2783: '_Select_invoke_traits<_Callable,_Args...>::type dosomething(Func &&,Args &&...)': could not deduce template argument for 'Func' Template_TEst.cpp(26): message : see declaration of 'dosomething' Done building project "Template_TEst.vcxproj" -- FAILED.
重命名其中一个getSomething重载函数后,代码可正常编译,疑问:这是重载解析问题还是模板定义的语法问题?
问题原因
这是重载解析问题,和模板定义的语法无关。
当你直接传递&Helper::getSomething时,该名称对应两个不同签名的重载函数,编译器无法自动推导到底要取哪个函数的地址。而模板函数dosomething的参数Func需要明确的类型信息才能完成模板参数推导,重载函数名本身不是一个确定的类型,因此推导失败。
重命名其中一个函数后,函数名唯一,编译器能确定对应的函数类型,自然可以正常推导模板参数并编译通过。
解决方法
方法1:显式指定模板参数类型
直接告诉编译器要选择的重载函数类型:
int main() { // 显式指定带参数的重载版本类型 std::cout << "Invoke " << dosomething<std::string(*)(const std::string&)>(&Helper::getSomething, "test"); // 显式指定无参数的重载版本类型 std::cout << "Invoke " << dosomething<std::string(*)()>(&Helper::getSomething); }
方法2:使用Lambda表达式包裹调用(更简洁)
利用Lambda内部的重载解析能力,将确定的调用逻辑传递给模板函数:
int main() { std::cout << "Invoke " << dosomething([]{ return Helper::getSomething("test"); }); std::cout << "Invoke " << dosomething([]{ return Helper::getSomething(); }); }
Lambda表达式的类型是确定的,编译器可以轻松完成模板参数推导,同时Lambda内部会自动匹配正确的重载函数。
内容的提问来源于stack exchange,提问作者Shivanand Naik
相关产品推荐
相关产品推荐

