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

如何在C++中通过参数包展开实现链式成员函数调用?

用参数包实现链式成员函数调用(以nlohmann json为例)

很多库(比如nlohmann json)的类型支持通过成员函数/运算符返回自身实例,实现链式调用,比如:

auto my_data = my_json_object["first key"]["second key"];

完全可以通过参数包实现自动展开链式调用,替代手动编写多层运算符调用。以下是几种可行的实现方式:

1. 递归展开参数包(兼容C++11及以上)

通过递归模板,逐步处理每个参数,每一步都调用目标运算符,再递归处理剩余参数:

#include <nlohmann/json.hpp>
using json = nlohmann::json;

// 基础终止条件:无额外参数时直接返回原对象
template <class Json>
auto get_elem(Json&& json)
{
    return std::forward<Json>(json);
}

// 递归处理参数包:先处理第一个键,再递归处理剩下的键
template <class Json, class FirstKey, class... RestKeys>
auto get_elem(Json&& json, FirstKey&& first_key, RestKeys&&... rest_keys)
{
    return get_elem(
        std::forward<Json>(json)[std::forward<FirstKey>(first_key)],
        std::forward<RestKeys>(rest_keys)...
    );
}

// 使用示例
int main()
{
    json my_json_object = {
        {"first key", {{"second key", "hello world"}}}
    };
    auto my_data = get_elem(my_json_object, "first key", "second key");
    // my_data == "hello world"
}

这种方式兼容性强,C++11就能使用,运行时无额外开销,仅编译阶段会生成递归展开的代码。

2. C++17折叠表达式(更简洁)

利用C++17引入的折叠表达式,一行代码完成参数包的展开,写法更紧凑:

#include <nlohmann/json.hpp>
using json = nlohmann::json;

template <class Json, class... Keys>
auto get_elem(Json&& json, Keys&&... keys)
{
    auto result = std::forward<Json>(json);
    // 左折叠表达式:依次将每个键应用到当前结果上
    (result = result[std::forward<Keys>(keys)], ...);
    return result;
}

折叠表达式会自动展开为result = result[key1]; result = result[key2]; ...,最终效果和手动链式调用完全一致。

3. 优化:支持const对象与避免拷贝

如果需要和原生链式调用完全一致(比如返回引用而非拷贝,支持const对象),可以重载const和非const版本的函数:

#include <nlohmann/json.hpp>
using json = nlohmann::json;

// const版本:返回const引用,避免修改原对象
template <class... Keys>
const auto& get_elem(const json& json, Keys&&... keys)
{
    const auto* current = &json;
    ((*current = &(*current)[std::forward<Keys>(keys)]), ...);
    return *current;
}

// 非const版本:返回可修改的引用
template <class... Keys>
auto& get_elem(json& json, Keys&&... keys)
{
    auto* current = &json;
    ((*current = &(*current)[std::forward<Keys>(keys)]), ...);
    return *current;
}

这种实现可以避免不必要的对象拷贝,完全复刻原生链式调用的行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 13:25:50