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

C++17下如何实现调用不同参数成员函数的监听器通知模板?

实现C++17下支持多参数成员函数的监听器通知模板

问题场景

你需要一个通用模板函数,遍历不同类型的监听器列表,调用它们各自参数不同的成员函数,比如IFooListener::Foo(int, double, std::string)和IBarListener::Bar(std::string, std::string),并且希望能像这样调用:

notifyListeners(fooListeners, &IFooListener::Foo, 1, 2.0, "Bla");
notifyListeners(barListeners, &IBarListener::Bar, "one", "two");

解决方案

可以利用C++17的可变参数模板和完美转发来实现,不需要依赖std::function,直接传递成员函数指针即可。同时可以添加编译期检查,确保传入的成员函数属于监听器类型。

完整实现代码如下:

#include <vector>
#include <utility>
#include <type_traits>

// 辅助模板:编译期检查成员函数是否属于目标监听器类型
template <typename T, typename MemFunc>
struct is_valid_member_function : std::false_type {};

template <typename T, typename Ret, typename... Args>
struct is_valid_member_function<T, Ret(T::*)(Args...)> : std::true_type {};

template <typename T, typename Ret, typename... Args>
struct is_valid_member_function<T, Ret(T::*)(Args...) const> : std::true_type {};

template <typename T, typename MemFunc, typename... Args>
void notifyListeners(std::vector<T*> listeners, MemFunc memfunc, Args&&... args) {
    // 编译期校验:确保传入的是当前监听器类型的成员函数
    static_assert(is_valid_member_function<T, MemFunc>::value, 
                  "memfunc must be a member function of the listener type");

    for (auto listener : listeners) {
        if (listener != nullptr) { // 空指针检查,避免程序崩溃
            // 调用成员函数,完美转发参数减少拷贝
            (listener->*memfunc)(std::forward<Args>(args)...);
        }
    }
}

// 示例监听器接口类
class IFooListener {
public: // 成员函数需设为public,否则外部无法调用
    virtual void Foo(int, double, std::string) = 0;
    virtual ~IFooListener() = default;
};

class IBarListener {
public:
    virtual void Bar(std::string, std::string) = 0;
    virtual ~IBarListener() = default;
};

// 使用示例
int main() {
    std::vector<IFooListener*> fooListeners;
    std::vector<IBarListener*> barListeners;

    // 假设已添加具体的监听器实例
    notifyListeners(fooListeners, &IFooListener::Foo, 1, 2.0, "Bla");
    notifyListeners(barListeners, &IBarListener::Bar, "one", "two");
}

核心细节说明

  • 可变参数模板:Args&&... args接收任意数量、任意类型的参数,通过std::forward实现完美转发,避免不必要的对象拷贝。
  • 成员函数指针调用:使用(listener->*memfunc)(...)的标准语法调用成员函数,这是C++中调用成员函数指针的固定写法。
  • 编译期检查:通过自定义模板is_valid_member_function,在编译阶段就验证成员函数的合法性,提前暴露错误而非运行时崩溃。
  • 空指针防护:遍历监听器时判断指针是否为空,避免空指针解引用导致的程序异常。
  • 访问权限:监听器的成员函数必须设为public(接口类通常会把纯虚函数设为public),否则外部无法调用。

内容的提问来源于stack exchange,提问作者Frank

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 09:50:26