Как лямбда-макрос создает лямбду? - PullRequest
20 голосов
/ 30 января 2020

Я нашел этот кусок кода на 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 и как он возвращает указатель на функцию?

Ответы [ 2 ]

10 голосов
/ 30 января 2020

Используя этот макрос,

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; }
    _;
});

В фигурных скобках это использует G CC Вложенные функции для создать функцию, которая выполняет нужную операцию. Во внутренней области он имеет имя _.

Затем, как отмечает interjay, используются G CC ' Выражения операторов . Фактически функция _ назначается указателю 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);
}

Три метода можно сравнить в этом примере кода .

7 голосов
/ 30 января 2020

Это называется операторным выражением и создает «лямбду» (или вложенную функцию ) и возвращает на нее указатель. Это GNU C -specifi 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 - это тип возвращаемого значения "лямбда". _ - это имя функции, используемой внутри него, потому что это необычное имя идентификатора. _body состоит из аргументов и тела функции. Трейлинг _ "возвращает" "лямбду".

Этот код находится в Let's Destroy C (это подходящее имя). Вы не должны использовать это. Это заставит ваш код работать только на компиляторах, которые поддерживают расширения GNU C. Вместо этого просто напишите функцию или макрос.

Если вы часто используете подобные конструкции или хотите больше возможностей, я предлагаю использовать C ++. С C ++ вы можете сделать что-то похожее на это и иметь переносимый код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...