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

基于std::tuple与折叠表达式实现类Lisp风格的C++函数调用

实现C++中类Lisp风格的嵌套函数调用

你已经迈出了很好的第一步,用std::tuple封装函数和参数的思路完全可行,但当前代码的问题在于没有处理嵌套元组的递归求值——当某个参数本身是另一个函数元组时,你的代码只会把它当作普通参数传递,而不会先执行这个嵌套函数。

解决这个问题的核心是编写一个递归的求值函数,它能自动识别并解析嵌套的函数元组:如果传入的是普通值,直接返回;如果是封装了函数和参数的元组,就先递归求值所有参数(包括嵌套的函数元组),再调用目标函数。

完整实现代码

#include <iostream>
#include <tuple>
#include <functional>

// 基础情况:处理普通值,直接返回
template<typename T>
constexpr auto eval(T&& val) {
    return std::forward<T>(val);
}

// 递归情况:处理函数元组(第一个元素是可调用对象,第二个是参数元组)
template<typename Func, typename... Args>
constexpr auto eval(const std::tuple<Func, std::tuple<Args...>>& func_tuple) {
    // 取出函数和参数元组
    const auto& func = std::get<0>(func_tuple);
    const auto& args_tuple = std::get<1>(func_tuple);
    
    // 递归求值每个参数,再传递给函数
    return std::apply([&func](auto&&... evaluated_args) {
        return func(std::forward<decltype(evaluated_args)>(evaluated_args)...);
    }, std::apply([](auto&&... args) {
        return std::make_tuple(eval(std::forward<decltype(args)>(args))...);
    }, args_tuple));
}

int main() {
    // 定义示例函数:求和
    auto add = [](auto... args) { return (args + ...); };
    
    // 构造类Lisp嵌套调用:(add 10 5 (add 3 2))
    auto nested_call = std::make_tuple(
        add,
        std::make_tuple(
            10,
            5,
            std::make_tuple(add, std::make_tuple(3, 2))
        )
    );
    
    // 求值并输出结果
    auto result = eval(nested_call);
    std::cout << result << std::endl; // 输出 20
    
    return 0;
}

代码解释

  1. 递归eval函数:

    • 第一个模板是基础分支,接收普通类型(比如int、double),直接返回原值。
    • 第二个模板专门处理函数元组:先提取函数和参数元组,然后用std::apply遍历参数元组的每个元素,对每个元素递归调用eval(这样嵌套的函数元组会被先执行),最后把求值后的参数传递给目标函数执行。
  2. 嵌套调用的构造:
    对应Lisp的(fun1 a b (fun2 c d)),我们用std::make_tuple嵌套构造:外层是make_tuple(fun1, make_tuple(a, b, make_tuple(fun2, make_tuple(c, d)))),完全贴合Lisp的嵌套结构。

  3. 折叠表达式的作用:
    你的add函数已经用到了折叠表达式(args + ...)来实现可变参数求和,而我们在eval的参数处理中,用std::make_tuple(eval(args)...)的折叠表达式来批量处理所有参数的递归求值。

扩展说明

  • 这个实现支持任意深度的嵌套调用,只要保持(函数, 参数元组)的结构即可。
  • 兼容C++17及以上版本,因为用到了std::apply、折叠表达式、自动模板参数等特性。
  • 可以扩展支持更多类型的可调用对象,比如普通函数、Lambda、成员函数(需要绑定)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 04:42:43