【问题标题】:How does the lambda macro create a lambda?lambda 宏如何创建 lambda?
【发布时间】:2020-05-16 07:39:45
【问题描述】:

我在 GitHub 上找到了这段代码,但不太明白:

#define lambda(ret_type, _body) ({ ret_type _ _body _; })

然后:

int (*max)(int, int) = lambda(int,
                             (int x, int y) {
                                 return x > y ? x : y;
                             });

int max_value = max(1, 2);
// max_value is 2

#define 中的下划线是做什么用的,它是如何返回函数指针的?

【问题讨论】:

  • 您是否尝试过仅扩展宏(例如使用gcc -E)来查看它的作用?
  • 请看展开godbolt.org/z/C5TLWj虽然结果不太好理解
  • 我假设您根据获得此代码的地点周围的 cmets 知道,但这确实依赖于嵌套函数的 GCC 扩展。
  • @EugeneSh。它通过使用 GCC 的嵌套函数来初始化函数指针。原始代码来自here。今天在 Hacker News 上分享了这个项目。
  • @EugeneSh。它是两个 GCC 扩展的组合:嵌套函数和 compound statements in expressions。嵌套函数出现在复合语句中。

标签: c gcc lambda macros function-pointers


【解决方案1】:

使用这个宏,

int (*max)(int, int) = lambda(int,
                              (int x, int y) {
                                  return x > y ? x : y;
                              });

扩展到:

int (*max)(int, int) = ({
    int _ (int x, int y) { return x > y ? x : y; }
    _;
});

在花括号中,它使用 GCC 的 Nested Functions 创建一个执行所需操作的函数。在内部范围内,它的名称为_

然后,正如 interjay 所指出的,使用 GCC 的 Statement Expressions。实际上,函数_ 被分配给了指针max

如果没有使用这样的宏,可以用不同的方式编写并用作:

int val1 = 4;
int val2 = -30;

int perform_operation(int (*op)(int, int)) {
    int new_val = op(val1, val2);
    val1 = val2;
    val2 = new_val;
    return new_val;
}

int enclosing_function (void) {
    // Create max "lambda"
    int (*max)(int, int);
    {
        // Curly braces limit the scope of _
        int _ (int x, int y) { return x > y ? x : y; }
        max = _;
    }

    return perform_operation(max);
}

这三种方法可以在this code example进行比较。

【讨论】:

  • 宏什么都不做,因为它不会在 gcc 中编译
  • @P__J__ 我在答案末尾添加了一个示例,该示例也显示了正在使用的此宏。
  • 为什么你不能使用max(4, -30); 而不是apply_binary_op(max, 4, -30);
  • @S.S.Anne 你可以。这只是您可以做什么的一个简单示例。我用一个不那么琐碎的案例更新了我的 sn-p 和链接示例。
  • “表达式中的复合语句”称为“语句表达式”。具有可以(例如)分配给某物的值的语句。
【解决方案2】:

这称为statement expression 并创建一个“lambda”(或nested function)并返回一个指向它的指针。它是 GNU C 特定的。

宏展开为:

int (*max)(int, int) = ({ int _ (int x, int y) { return x > y ? x : y; } _; })

末尾的_ 就像return

下划线实际上是创建和“返回”的函数的名称。之所以使用它是因为它是一个不常用的标识符(有充分的理由;_ 很可能是描述性最少的标识符)。

使用语句表达式的原因是_在语句表达式的范围退出后不会被定义。

所以,通过宏:

#define lambda(ret_type, _body) ({ ret_type _ _body _; })

ret_type 是“lambda”的返回类型。 _ 是其中使用的函数的名称,因为它是一个不常见的标识符名称。 _body 由函数的参数和主体组成。尾随的_“返回”“lambda”。

此代码位于Let's Destroy C(这是一个合适的名称)。你不应该使用它。它将使您的代码仅在支持 GNU C 扩展的编译器上工作。相反,只需编写一个函数或宏。

如果您经常使用这样的结构或想要更多功能,我建议您使用 C++。使用 C++,您可以执行类似的操作并且拥有可移植的代码。

【讨论】:

    猜你喜欢
    • 2017-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-26
    • 2020-12-21
    • 1970-01-01
    • 1970-01-01
    • 2019-02-28
    相关资源
    最近更新 更多