You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

模板无法解析重载函数: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 04:44:58