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

如何简化通过类Getter方法创建std::tuple的调用方式?

简化C++20多维度排序的Getter调用实现方案

针对你的需求,我们可以利用C++20的Concepts、编译期逻辑和宏简化,实现无需手动传入完整成员函数指针的调用方式,同时保证类型安全。

核心实现思路

通过编译期自动拼接deliver_前缀,结合Concepts校验类型是否拥有对应Getter方法,最终简化调用语法。以下是可直接落地的代码方案:

完整可编译代码

#include <tuple>
#include <vector>
#include <algorithm>
#include <concepts>
#include <type_traits>

// 基础Getter包装器,用于统一类型标识
struct GetterBase {};

// 模板:绑定具体成员函数的Getter包装器
template<typename ObjType, auto (ObjType::*GetterFunc)() const>
struct BoundGetter : GetterBase {
    static auto extract(const ObjType& obj) {
        return (obj.*GetterFunc)();
    }
};

// 核心宏:自动匹配Getter(优先找deliver_前缀,不存在则直接匹配传入名称)
#define AUTO_GET(NAME) \
    std::conditional_t< \
        requires(const Obj& obj) { obj.deliver_##NAME(); }, \
        BoundGetter<Obj, &Obj::deliver_##NAME>, \
        BoundGetter<Obj, &Obj::NAME> \
    >

// 多维度排序函数:支持任意数量的Getter参数
template<typename Obj, typename... Getters>
requires (std::derived_from<Getters, GetterBase> && ...)
void sort_by_getters(std::vector<Obj>& obj_list) {
    std::ranges::sort(obj_list, [](const Obj& a, const Obj& b) {
        return std::make_tuple(Getters::extract(a)...) < std::make_tuple(Getters::extract(b)...);
    });
}

// ------------------------------
// 示例使用
// ------------------------------
struct Agg {
    int deliver_j() const { return j_val; }
    std::string deliver_k() const { return k_str; }
    // 假设存在一个直接命名的Getter(用于测试直接匹配逻辑)
    double priority() const { return prio; }

    int j_val = 0;
    std::string k_str;
    double prio = 0.0;
};

int main() {
    std::vector<Agg> data;
    // 调用示例:直接传入j、deliver_k、priority,宏自动匹配对应Getter
    sort_by_getters<Agg, AUTO_GET(j), AUTO_GET(deliver_k), AUTO_GET(priority)>(data);
    return 0;
}

关键特性解析

  1. 类型安全校验:通过requires子句在编译期检查目标类型是否拥有对应Getter方法,不存在则直接编译报错,避免运行期错误。
  2. 自动前缀拼接:AUTO_GET宏会优先检查deliver_XXX形式的方法,不存在则尝试直接匹配XXX方法,完全符合你的需求。
  3. 适配C++20标准:使用std::ranges::sort替代传统std::sort,结合Concepts做编译期约束,符合现代C++风格。
  4. 扩展性强:新增Getter无需修改排序函数,只需在调用时传入对应的名称即可。

无宏替代方案(适合Getter数量较少的场景)

如果不想依赖宏,可以手动定义Getter标签并特化包装器,代码更直观但需要额外的定义工作:

// 定义Getter标签
struct JTag {};
struct DeliverKTag {};
struct PriorityTag {};

// 特化包装器,绑定到具体方法
template<>
struct BoundGetter<Agg, JTag> {
    static auto extract(const Agg& obj) { return obj.deliver_j(); }
};

template<>
struct BoundGetter<Agg, DeliverKTag> {
    static auto extract(const Agg& obj) { return obj.deliver_k(); }
};

template<>
struct BoundGetter<Agg, PriorityTag> {
    static auto extract(const Agg& obj) { return obj.priority(); }
};

// 调用方式
sort_by_getters<Agg, BoundGetter<Agg, JTag>, BoundGetter<Agg, DeliverKTag>, BoundGetter<Agg, PriorityTag>>(data);

这种方式完全避免宏,但需要为每个Getter手动编写标签和特化代码,适合Getter数量固定且较少的遗留系统。

内容的提问来源于stack exchange,提问作者Thomas G.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 19:04:54