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

C++通过map存储并调用类模板成员函数指针的方法

问题根源

你的代码有三处错误:

  1. 语法非法:成员指针调用运算符.*的右侧必须是成员指针类型的表达式,你写的(proxy2.&(it->second))()把取地址符&插在对象和成员指针中间,完全不符合C++语法,直接触发编译错误。
  2. 类型不兼容:C++标准不保证成员函数指针可以和void*互相转换,成员函数指针的内存长度、表示形式随继承模式、编译器实现变化,可能远大于普通void*的长度,强转存进void*属于未定义行为,随时可能崩溃。
  3. 野指针风险:你写的myMap[0]= &memfnptr存的是局部变量memfnptr的栈地址,等赋值语句执行完,这个栈地址的内容随时可能被覆盖,后续取出来就是无效值。
修正方案

如果你的map只需要存储同一个类实例化出的同签名成员函数指针(比如你示例里全是SomeServiceProxy<int>的无参返回void的成员函数),直接把map的value类型设为对应的成员函数指针类型即可,不需要用void*做中间层。
修正后的可运行代码:

#include <iostream>
#include <map>

template<typename... extensions>
class SomeServiceProxy
{
public:
    void DoSomething() {
        std::cout << "\ndoing sth\n";
    }
};

template<typename... extensions>
using DoSomethingFnPtr = void (SomeServiceProxy<extensions...>::*)();

// map值类型直接定义为对应实例的成员函数指针类型
std::map<int, DoSomethingFnPtr<int>> myMap;

int main()
{
    SomeServiceProxy<int> proxy;
    DoSomethingFnPtr<int> memfnptr = &SomeServiceProxy<int>::DoSomething;
    proxy.DoSomething();
    (proxy.*memfnptr)();
    // 直接存成员函数指针的值,不要存局部变量的地址
    myMap[0] = memfnptr;

    auto it = myMap.find(0);
    if(it != myMap.end() ){
        SomeServiceProxy<int> proxy2;
        // 取出存储的成员指针,用.*运算符调用,注意括号不能漏
        DoSomethingFnPtr<int> stored_ptr = it->second;
        (proxy2.*stored_ptr)();
    }

    std::cout << std::endl;
    return 0;
}

如果你需要在map里存储不同类、不同模板实例的成员函数,用类型擦除包装即可,比如借助std::function封装调用逻辑,不需要硬转void*:

#include <iostream>
#include <map>
#include <functional>

template<typename... extensions>
class SomeServiceProxy
{
public:
    void DoSomething() {
        std::cout << "\ndoing sth\n";
    }
};

// 统一包装为:传入对象地址,执行对应成员调用的可调用对象
std::map<int, std::function<void(void*)>> myMap;

int main()
{
    // 存入时包装好类型转换和调用逻辑
    myMap[0] = [](void* inst) {
        auto* obj = static_cast<SomeServiceProxy<int>*>(inst);
        obj->DoSomething();
    };

    auto it = myMap.find(0);
    if(it != myMap.end() ){
        SomeServiceProxy<int> proxy2;
        // 调用时传入对象实例地址即可
        it->second(&proxy2);
    }

    std::cout << std::endl;
    return 0;
}
注意事项
  • 永远不要用void*存储成员函数指针,这是C++开发中常见的未定义行为,哪怕个别编译器下临时跑通,换编译选项、类增加继承关系后会直接出现内存错误。
  • .*/->*运算符优先级低于函数调用运算符(),调用成员指针时必须把(实例.*成员指针)整体用括号包裹,再跟参数列表,否则会编译报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 12:36:20