ตัวแปรนิพจน์แลมบ์ดา c++ ในคลาส

ฉันต้องการบันทึกตัวแปรนิพจน์แลมบ์ดา (เช่นในบล็อกโค้ดกำปั้น) ปัญหาคือฉันใช้คลาส (เช่นบล็อกโค้ดที่สอง) คอมไพเลอร์ส่งคืนข้อผิดพลาดบางอย่างให้ฉัน ฉันไม่รู้วิธีแก้ไขมัน

ฉันหวังว่าจะมีคนช่วยฉันและอธิบายได้ว่าทำไมมันถึงไม่ทำงานแบบนี้ ขอบคุณ.

รหัสแรก:

// variable for function pointer
void (*func)(int);
// default output function
void my_default(int x) {
    cout << "x =" << "\t" << x << endl << endl;
}


int main() {
    cout << "Test Programm\n\n";

    // 1. Test - default output function
    cout << "my_default\n";
    func = &my_default;
    func(5);

    // 2. Test - special output function 2
    cout << "my_func2\n";
    func = [](int x) {  cout << "x =" << "  " << x << endl << endl; };
    func(5);

    return 0;
}

รหัสที่สอง:

class test {
private:
    // variable for function pointer
    void (*func)(int);
    // default output function
    void my_default(int x) {
        cout << "x =" << "\t" << x << endl << endl;
    }

public:
    void dummy(void) {
        // 1. Test - default output function
        cout << "my_default\n";
        func = &my_default;
        func(5);

        // 2. Test - special output function 2
        cout << "my_func2\n";
        func =  [](int x)->int{ cout << "x =" << "  " << x << endl << endl; };
        func(5);
    }
};


// entry
int main() {
    cout << "Test Programm\n\n";

    test a;
    a.dummy();

    return 0;
}

คอมไพเลอร์:

pi@raspberrypi ~/dev/property $ gcc -std=c++0x -o test2 test2.cpp -lstdc++
test2.cpp: In member function ‘void test::dummy()’:
test2.cpp:491:17: error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.  Say ‘&test::my_default’ [-fpermissive]
test2.cpp:491:17: error: cannot convert ‘void (test::*)(int)’ to ‘void (*)(int)’ in assignment
test2.cpp:496:77: error: invalid user-defined conversion from ‘test::dummy()::<lambda(int)>’ to ‘void (*)(int)’ [-fpermissive]
test2.cpp:496:28: note: candidate is: test::dummy()::<lambda(int)>::operator int (*)(int)() const <near match>
test2.cpp:496:28: note:   no known conversion for implicit ‘this’ parameter from ‘int (*)(int)’ to ‘void (*)(int)’

person Heinrich    schedule 28.01.2014    source แหล่งที่มา
comment
ตัวชี้ฟังก์ชันสมาชิกไม่เหมือนกับตัวชี้ฟังก์ชัน คุณสามารถเห็นข้อผิดพลาดว่าประเภทต่างกัน   -  person chris    schedule 29.01.2014
comment
นอกจากคำตอบด้านล่างแล้ว... lambda ของคุณใน test2.cpp ล้มเหลวเนื่องจากส่งคืน int แทนที่จะเป็นโมฆะ   -  person Rastaban    schedule 29.01.2014


คำตอบ (2)


ปัญหาคือฟังก์ชันสมาชิกไม่ใช่ฟังก์ชันปกติ ไม่สามารถกำหนดให้กับตัวชี้ฟังก์ชันได้เนื่องจากประเภทที่เป็นสมาชิกเป็นส่วนหนึ่งของประเภท นอกจากนี้ ฟังก์ชันสมาชิกจำเป็นต้องมีอ็อบเจ็กต์ที่จะเรียกใช้ ซึ่งจะเป็น this ที่อยู่ในโค้ดฟังก์ชัน

คุณมีวิธีแก้ปัญหาหลายประการ:

  1. อนุญาตเฉพาะฟังก์ชันที่เป็นสมาชิกของชั้นเรียนของคุณ

    void (*MyClass::func)(int); // but you can use it only with members of the class
    
  2. ใช้ std::function

    typedef std::function<void(int)> func;
    

โซลูชันที่ 2 นั้นเป็นวิธีที่ง่ายที่สุดเนื่องจาก std::function ได้รับการออกแบบมาเพื่อทำงานกับทุกสิ่งที่สามารถเรียกได้ด้วยลายเซ็นเดียวกันกับที่อยู่ในพารามิเตอร์เทมเพลต นอกจากนี้ยังเป็นโซลูชันเดียวที่ช่วยให้คุณสามารถจัดเก็บการปิด (วัตถุจากแลมบ์ดา) ดู C++11 styled callbacks? เพื่อดูรายละเอียด

class test {
private:
    // variable for function pointer
    std::function< void ( int )> func;
    // default output function
    void my_default(int x) {
        cout << "x =" << "\t" << x << endl << endl;
    }

public:
    void dummy(void) {
        // 1. Test - default output function
        cout << "my_default\n";
        func = std::bind(&test::my_default, this, std::placeholders::_1);
        // or 
        func = [&]( int i ){ my_default( i ); };
        func(5);

        // 2. Test - special output function 2
        cout << "my_func2\n";
        func =  [](int x)->int{ cout << "x =" << "  " << x << endl << endl; };
        func(5);
    }
};


// entry
int main() {
    cout << "Test Programm\n\n";

    test a;
    a.dummy();

    return 0;
}
person Klaim    schedule 28.01.2014
comment
ขอบคุณสำหรับคำอธิบาย func = std::bind( &my_default, this ); จะส่งกลับข้อผิดพลาด (คอมไพเลอร์) แต่เหมือนกับที่ Brian Bi เขียน std::bind(&test::my_default, this, std::placeholders::_1); จะไม่ส่งคืนข้อผิดพลาด - person Heinrich; 29.01.2014
comment
อ๋อ ใช่ ฉันมักมีช่วงเวลาที่ยากลำบากในการเตือนวิธีใช้ bind ดังนั้นฉันจึงใช้ lambdas เท่านั้น นอกจากนี้ยังมี mem_fun() - person Klaim; 29.01.2014
comment
ฉันขอแนะนำเส้นทาง std::function แม้ว่าตัวเลือกที่สาม (ขึ้นอยู่กับลักษณะของ my_default) คือการทำให้ my_default คงที่ - person Rastaban; 29.01.2014
comment
@Rastaban เขาต้องการใช้ lambdas และเราไม่รู้ว่ามันจับ lambdas หรือไม่ - person Klaim; 29.01.2014

ฟังก์ชันสมาชิกไม่เหมือนกับฟังก์ชันทั่วไป โดยจะต้องมีอินสแตนซ์ของคลาสที่พร้อมใช้งานจึงจะเรียกใช้ได้ (เช่น วัตถุที่จะกลายเป็น *this) คุณไม่สามารถทำให้ตัวแปรตัวชี้ฟังก์ชันธรรมดาชี้ไปที่ฟังก์ชันสมาชิกได้

หากคุณต้องการสร้างตัวชี้ฟังก์ชันที่สามารถเรียกได้โดยใช้อินสแตนซ์ใดๆ ของคลาส คุณต้องมีตัวชี้ฟังก์ชันสมาชิก คุณจะเขียน

void (test::*func)(int);

เพื่อประกาศมัน

func = &test::my_default;

เพื่อมอบหมายและ

(this->*func)(5);

ที่จะเรียกมัน แน่นอน ตอนนี้คุณไม่สามารถทำให้ตัวชี้ฟังก์ชันสมาชิกชี้ไปที่แลมบ์ดาได้

ในทางกลับกัน หากคุณต้องการผูก this เป็นอินสแตนซ์และสร้างฟังก์ชันธรรมดาจากฟังก์ชันสมาชิก คุณไม่สามารถสร้างตัวชี้ฟังก์ชันธรรมดาให้กับฟังก์ชันดังกล่าวได้ คุณจะต้องการวัตถุ std::function แทน

std::function<void(int)> func;

ผูกไว้ดังนี้:

func = std::bind(&test::my_default, this, std::placeholders::_1);

แล้วโทรไปตามปกติ std::function ใช้งานได้กับแลมบ์ดาเหมือนกับที่ตัวชี้ฟังก์ชันทำ

person Brian Bi    schedule 28.01.2014
comment
ขอบคุณ!! ฉันอาจลืมไปแล้วว่าฟังก์ชันสมาชิกกับฟังก์ชันธรรมดาแตกต่างกันอย่างไร - person Heinrich; 29.01.2014