You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何简化C++中根据指针类型判断调用同名函数的重复代码?

如何简化C++中根据指针类型判断调用同名函数的重复代码?

这种反复写is_A(ptr) ? use_A(ptr)->f() : use_B(ptr)->f()的代码确实够啰嗦的,不仅写着麻烦,后期要加新的同名函数时还要重复一遍判断逻辑,很容易出错。我给你几个轻量又高效的解决方案,完全避开虚函数的性能问题:

方案一:模板+Lambda实现静态分发(推荐)

这是类型安全且最灵活的方式,编译期就能完成所有分支展开,运行时性能和手写三元判断完全一致,没有任何额外开销。

先写一个通用的分发模板函数:

template <typename Func>
auto dispatch(uintptr_t ptr, Func func) {
    if (is_A(ptr)) {
        return func(use_A(ptr));
    } else {
        // 这里可以加断言确保ptr是B类型,避免非法情况
        return func(use_B(ptr));
    }
}

之后调用同名函数就变得非常简洁,不管是fg还是带参数的函数都能轻松处理:

// 调用f函数
auto answer_f = dispatch(ptr, [](auto* obj) { return obj->f(); });
// 调用g函数
auto answer_g = dispatch(ptr, [](auto* obj) { return obj->g(); });
// 如果函数带参数,比如f(int x)
int x = 10;
auto answer_f_with_arg = dispatch(ptr, [x](auto* obj) { return obj->f(x); });

这个方案的好处是,Lambda可以封装任意复杂的调用逻辑,模板会自动推导返回类型,完全不用担心类型不匹配的问题,维护起来也省心。

方案二:调整宏的写法(适合简单场景)

你之前尝试的宏报错,可能是实际场景中函数的引用方式和示例不同(比如不是直接的标识符)。如果还是想用宏,针对成员函数可以调整成这样:

#define CALL_MEMBER_FUNC(ptr, mem_func) \
    (is_A(ptr) ? (use_A(ptr)->*mem_func)() : (use_B(ptr)->*mem_func)())

调用的时候需要传入成员函数的指针:

auto answer_f = CALL_MEMBER_FUNC(ptr, &A::f);
auto answer_g = CALL_MEMBER_FUNC(ptr, &A::g);

不过宏的缺点是类型安全差一些,遇到复杂场景(比如带参数、返回类型不同)容易出问题,所以更推荐第一种模板+Lambda的方式。

补充说明

你提到虚函数性能差,这两个方案都是静态分发,编译时就把分支逻辑展开成了和手写判断一样的代码,完全没有虚函数的运行时开销,绝对符合你要的“轻量”需求。

内容来源于stack exchange

火山引擎 最新活动