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

C++如何消重重载类成员函数并获取其首个参数的类型

解决方案

核心思路是利用SFINAE让编译器根据传入的实参类型,自动从重载集中筛选出匹配的成员函数,再提取对应的形参类型,完整可运行的实现如下:

#include <type_traits>

class Abase {
public:
    void fun2() {
        // Success!
    }
};
class C {void fun2() {};};
class A1 : public Abase {};
class A2 : public Abase {};
class A : public A1, public A2 {};


class B {
public:
    void fun1(A1* t) {}
    void fun1(C* t) {}
};

// 辅助元工具:推导传入Arg类型参数时,Obj::fun1匹配的第一个形参类型
template <typename Obj, typename Arg>
struct get_matched_fun1_param {
private:
    // SFINAE筛选可以接受Arg类型转换的重载
    template <typename Ret, typename ParamType>
    static typename std::enable_if<
        std::is_convertible<Arg, ParamType>::value,
        ParamType
    >::type test(Ret(Obj::* f)(ParamType));
public:
    using type = decltype(test(&Obj::fun1));
};

template <typename Obj, typename Arg>
using get_matched_fun1_param_t = typename get_matched_fun1_param<Obj, Arg>::type;

template <typename T1,typename T2>
void problematic(T1* a, T2* b)
{
    b->fun1(a);
    // 自动匹配重载得到参数类型完成转换
    static_cast<get_matched_fun1_param_t<T2, T1*>>(a)->fun2();
}
int main()
{
    A a;
    B b;
    problematic(&a, &b);
}

原理解释

  • 直接取重载成员函数的地址会有歧义,因为编译器不知道需要选择哪个版本的重载,我们通过std::is_convertible添加SFINAE约束,让编译器只保留能接受当前传入实参类型的重载。
  • 当有且仅有一个重载满足转换要求时,decltype就能正确推导得到对应形参的类型,和实际调用fun1时的重载决议结果完全一致。
  • 如果存在多个满足转换要求的重载,会直接编译报错,和普通调用重载函数出现歧义的表现一致,符合预期。

如果需要适配任意名称的成员函数,可以通过宏封装上述逻辑,C++11暂不支持将函数名作为模板参数直接传递。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 21:45:04