模板无法解析重载函数:C++参数包问题求助
解决C++模板无法解析重载成员函数的问题
问题代码
#include <iostream> #include <algorithm> #include <memory> #include <mutex> #include <vector> template <typename Observer> class ObsNoti { public: template < typename Ret, typename Class, typename... Args, typename = std::enable_if_t<std::is_same<Observer, Class>::value>> void notifyEveryone(Ret Class::*func, Args&&... args) { (obs.*func)(std::forward<Args>(args)...); } Observer obs; }; class ContactObserver { public: virtual int onContactRetrieved() { std::cout<<"onContactRetrieved\n"; return 0; } virtual int onContactRetrieved(bool bSucess) { std::cout<<"onContactRetrieved sucessfully\n"; return 0; } }; class MyClass : public ObsNoti<ContactObserver> { public: template<typename Func, bool, typename... Args> inline void notifyObserver(Func &&func, bool b, Args&&... args) { ObsNoti<ContactObserver>::notifyEveryone(func , b, std::forward<Args>(args)...); } template<typename Func, typename... Args> inline void notifyObserver(Func &&func, Args&&... args) { ObsNoti<ContactObserver>::notifyEveryone(func , std::forward<Args>(args)...); } }; int main() { MyClass my; my.notifyObserver(&ContactObserver::onContactRetrieved, true); return 0; }
编译错误
/tmp/w7Rta4F1cT.cpp:53:22: error: no matching function for call to 'MyClass::notifyObserver(<unresolved overloaded function type>, bool)' 53 | my.notifyObserver(&ContactObserver::onContactRetrieved, true); | ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /tmp/w7Rta4F1cT.cpp:37:17: note: candidate: 'template<class Func, bool <anonymous>, class ... Args> void MyClass::notifyObserver(Func&&, bool, Args&& ...)' 37 | inline void notifyObserver(Func &&func, bool b, Args&&... args) { | ^~~~~~~~~~~~~~ /tmp/w7Rta4F1cT.cpp:37:17: note: template argument deduction/substitution failed: /tmp/w7Rta4F1cT.cpp:53:22: note: couldn't deduce template parameter 'Func' 53 | my.notifyObserver(&ContactObserver::onContactRetrieved, true); | ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /tmp/w7Rta4F1cT.cpp:42:17: note: candidate: 'template<class Func, class ... Args> void MyClass::notifyObserver(Func&&, Args&& ...)' 42 | inline void notifyObserver(Func &&func, Args&&... args) { | ^~~~~~~~~~~~~~ /tmp/w7Rta4F1cT.cpp:42:17: note: template argument deduction/substitution failed: /tmp/w7Rta4F1cT.cpp:53:22: note: couldn't deduce template parameter 'Func' 53 | my.notifyObserver(&ContactObserver::onContactRetrieved, true); | ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
问题核心:&ContactObserver::onContactRetrieved对应两个重载函数签名,模板参数推导阶段编译器无法自动确定要使用哪个版本,导致无法推断Func类型。
解决方案
方法1:显式指定函数指针类型
调用时通过static_cast明确告诉编译器目标重载函数的类型:
int main() { MyClass my; // 显式转换到带bool参数的重载版本 my.notifyObserver( static_cast<int (ContactObserver::*)(bool)>(&ContactObserver::onContactRetrieved), true ); return 0; }
方法2:简化模板设计
删除MyClass中冗余的notifyObserver模板,直接匹配ObsNoti的成员函数签名,减少推导复杂度:
class MyClass : public ObsNoti<ContactObserver> { public: template<typename Ret, typename... Args> inline void notifyObserver(Ret (ContactObserver::*func)(Args...), Args&&... args) { ObsNoti<ContactObserver>::notifyEveryone(func, std::forward<Args>(args)...); } };
调用时依然需要显式转换或提前声明函数指针:
int main() { MyClass my; // 方式A:直接转换 my.notifyObserver( static_cast<int (ContactObserver::*)(bool)>(&ContactObserver::onContactRetrieved), true ); // 方式B:提前声明函数指针变量 auto targetFunc = static_cast<int (ContactObserver::*)(bool)>(&ContactObserver::onContactRetrieved); my.notifyObserver(targetFunc, true); return 0; }
方法3:用Lambda包装重载函数
通过Lambda捕获成员函数调用,避免直接传递重载函数指针,同时扩展模板支持可调用对象:
首先修改ObsNoti的notifyEveryone,增加对可调用对象的支持:
template <typename Observer> class ObsNoti { public: // 支持成员函数指针 template < typename Ret, typename Class, typename... Args, typename = std::enable_if_t<std::is_same<Observer, Class>::value>> void notifyEveryone(Ret Class::*func, Args&&... args) { (obs.*func)(std::forward<Args>(args)...); } // 支持Lambda、函数对象等可调用类型 template<typename Func, typename... Args> void notifyEveryone(Func&& func, Args&&... args) { std::forward<Func>(func)(std::forward<Args>(args)...); } Observer obs; };
调用时使用Lambda包装:
int main() { MyClass my; my.notifyObserver([&](bool b) { my.obs.onContactRetrieved(b); }, true); return 0; }
关键原理
重载函数的地址本身是“未解析的重载类型”,编译器需要明确的类型信息才能确定选择哪个版本。模板参数推导阶段无法自动完成这个选择,必须通过显式类型转换、提前声明变量或包装成Lambda等方式,给编译器提供明确的目标函数签名。
内容的提问来源于stack exchange,提问作者51k
相关产品推荐
相关产品推荐

