มาโครแลมบ์ดาสร้างแลมบ์ดาได้อย่างไร


20

ฉันพบรหัสชิ้นนี้ใน 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และมันคืนตัวชี้ฟังก์ชันได้อย่างไร


7
คุณลองขยายมาโคร (เช่นด้วยgcc -E) เพื่อดูว่ามันทำอะไร?
ไร้ประโยชน์

5
โปรดดูที่การขยายตัวgodbolt.org/z/C5TLWjผลลัพธ์ไม่ใช่เรื่องง่ายที่จะเข้าใจ
Eugene Sh

2
ฉันคิดว่าคุณรู้ตามความคิดเห็นรอบ ๆ จุดที่คุณได้รับรหัสนี้ แต่จะขึ้นอยู่กับส่วนขยาย GCC สำหรับฟังก์ชั่นที่ซ้อนกัน
Thomas Jager

4
@EugeneSh มันเริ่มต้นตัวชี้ฟังก์ชั่นโดยใช้ฟังก์ชั่นที่ซ้อนกันของ GCC รหัสเดิมจากที่นี่ โปรเจคนี้มีการแชร์ใน Hacker News วันนี้
Thomas Jager

4
@EugeneSh มันรวมกันของทั้งสองส่วนขยาย GCC: ฟังก์ชั่นที่ซ้อนกันและงบสารประกอบในการแสดงออก ฟังก์ชั่นที่ซ้อนกันปรากฏขึ้นภายในคำสั่งผสม
ระหว่าง

คำตอบ:


10

ใช้มาโครนี้

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 เพื่อสร้างฟังก์ชันที่ดำเนินการตามที่ต้องการ _ภายในขอบเขตด้านในก็มีชื่อ

จากนั้นตามที่ระบุไว้โดย interjay จะมีการใช้คำชี้แจงของ GCC ได้อย่างมีประสิทธิภาพฟังก์ชั่นได้รับมอบหมายให้ตัวชี้_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);
}

สามารถเปรียบเทียบทั้งสามวิธีได้ในตัวอย่างรหัสนี้


มาโครไม่ทำอะไรเลยเนื่องจากไม่ได้รวบรวมเป็น gcc
P__J__

@P__J__ มันจะรวบรวมideone.com/T5FLXb
Eugene Sh

@P__J__ ฉันได้เพิ่มตัวอย่างในตอนท้ายของคำตอบของฉันที่ยังแสดงให้เห็นว่าแมโครนี้ถูกใช้
Thomas Jager

ทำไมคุณไม่สามารถทำmax(4, -30);แทนapply_binary_op(max, 4, -30);?
SS Anne

1
"Compound Statement ในนิพจน์" เรียกว่า "statement expressions" ประโยคที่มีค่าที่สามารถกำหนด (เช่น) ให้กับบางสิ่งได้
Peter Cordes

7

สิ่งนี้เรียกว่าการแสดงออกของคำสั่งและสร้าง "แลมบ์ดา" (หรือฟังก์ชั่นที่ซ้อนกัน ) และส่งกลับตัวชี้ไปที่มัน เป็น GNU C-specific

แมโครขยายเป็น:

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ประกอบด้วยข้อโต้แย้งและเนื้อหาของฟังก์ชัน ส่วนท้าย_"ส่งคืน" the "lambda"

รหัสนี้พบได้ที่Let's Destroy C (ซึ่งเป็นชื่อที่เหมาะสม) คุณไม่ควรใช้มัน มันจะทำให้โค้ดของคุณใช้งานได้กับคอมไพเลอร์ที่รองรับส่วนขยาย GNU C เท่านั้น ให้เขียนฟังก์ชันหรือแมโครแทน

หากคุณใช้โครงสร้างเช่นนี้มากหรือต้องการคุณสมบัติเพิ่มเติมฉันขอแนะนำให้ใช้ C ++ ด้วย C ++ คุณสามารถทำสิ่งที่คล้ายกับสิ่งนี้และมีรหัสพกพา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.