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

如何为C++成员函数生成唯一键以用于unordered_map?

解决C++20 Mock类无需手动传函数名生成唯一成员函数键的方案

核心思路

利用C++17起支持的**auto模板参数**,将成员函数指针直接作为模板参数传入,通过编译期生成的唯一静态变量地址作为unordered_map的键,彻底避免手动传入函数名字符串。

完整实现代码

#include <unordered_map>
#include <any>
#include <type_traits>
#include <cassert>

template<typename T>
class Mock {
private:
    // 用静态变量的唯一地址作为键,存储对应返回值
    std::unordered_map<const void*, std::any> m_return_values;

    // 针对每个成员函数指针,生成唯一静态变量,返回其地址作为键
    template<auto MemFunc>
    static const void* get_unique_key() {
        static const char dummy; // 每个MemFunc对应唯一的dummy实例
        return &dummy;
    }

public:
    // 设置成员函数的返回值:自动推导返回值类型,无需传函数名
    template<auto MemFunc, typename Ret = std::invoke_result_t<decltype(MemFunc), T&>>
    void set_return(Ret&& ret) {
        const void* key = get_unique_key<MemFunc>();
        m_return_values[key] = std::forward<Ret>(ret);
    }

    // 获取成员函数的返回值:直接通过成员函数指针定位
    template<auto MemFunc, typename Ret = std::invoke_result_t<decltype(MemFunc), T&>>
    Ret get_return() {
        const void* key = get_unique_key<MemFunc>();
        return std::any_cast<Ret>(m_return_values.at(key));
    }
};

// 测试用例
class Foo {
public:
    virtual int f() = 0;
    virtual int g() = 0;
    virtual std::string hello() = 0;
};

int main() {
    Mock<Foo> mock;

    // 期望的简化调用方式:直接传成员函数指针,无需函数名
    mock.set_return<&Foo::f>(42);
    mock.set_return<&Foo::g>(69);
    mock.set_return<&Foo::hello>("Hello Mock!");

    assert(mock.get_return<&Foo::f>() == 42);
    assert(mock.get_return<&Foo::g>() == 69);
    assert(mock.get_return<&Foo::hello>() == "Hello Mock!");
}

关键细节说明

  1. 编译期唯一键生成:
    对于每个不同的成员函数指针MemFunc,模板函数get_unique_key<MemFunc>会生成一个独立的静态变量dummy,其内存地址在整个程序生命周期中是唯一的,完美解决同签名成员函数的区分问题。

  2. 自动类型推导:
    利用std::invoke_result_t自动推导成员函数的返回值类型,无需手动指定,进一步简化调用逻辑。

  3. 重载成员函数处理:
    如果存在重载的成员函数,只需显式指定成员函数的类型即可,例如:

    class Foo {
    public:
        int f();
        int f(int);
    };
    
    // 区分重载的f()和f(int)
    mock.set_return<static_cast<int (Foo::*)()>(&Foo::f)>(100);
    mock.set_return<static_cast<int (Foo::*)(int)>(&Foo::f)>(200);
    
  4. 标准合规性:
    该方案完全符合C++标准,没有使用任何未定义行为,跨平台兼容性良好。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 00:25:09