c++ - لماذا لا يمكن أن يكون عضو البيانات في قائمة التقاط لامبدا



c++11 lambda (3)

يمكنك التقاط أعضاء الفصل بقول this في قائمة الالتقاط. هذا لا علاقة له بحقيقة أن العضو هو const .

مثال:

#include <iostream>

struct Foo
{
    const int a = 0;
    int b;
    Foo() : b{42} {
        auto f = [this]() { std::cout << a << " " << b << std::endl; };
//                ^^^^ 
        f();
    }
};

int main() {
    Foo x;
}

لدي فئة foo يحتوي على bar كمتغير عضو.

في وظيفة عضو أخرى من الفصل ، أكتب وظيفة لامدا:

[bar](void){}

ولكن لا يمكنني تضمين bar في قائمة الالتقاط. لماذا هذا؟


يمكن التقاط الكائنات ذات مدة التخزين التلقائي فقط بواسطة لامدا في C ++ 11 (أي المتغيرات المحلية والمعلمات الوظيفية). إذا كنت تريد تأثير التقاط عضو بيانات فئة non-static ، فيمكنك إما التقاط this المؤشر كما في إجابة Danvil :

auto f = [this]{ std::cout << a << std::endl; };

أو تخزين قيمة العضو في ذاكرة التخزين المؤقت في متغير محلي والتقاط ذلك:

auto a = this->a;
auto f = [a]{ std::cout << a << std::endl; };

والذي سيكون أكثر إيجازًا في C ++ 14:

auto f = [a = this->a]{ std::cout << a << std::endl; };

يعتمد الاختيار بين هذين الخيارين على ما إذا كنت تريد تخزين القيمة الموجودة الآن أو إذا كنت ترغب في استرداد القيمة الموجودة عند استدعاء lambda . لاحظ أنه في حالة التقاط this يجب عليك التأكد من أن عمر كائن المؤشر يحيط عمر lambda استدعاء lambda بعد إتلاف الكائن له سلوك غير معروف. والحالة الأكثر بساطة التي تلتقط نسخة من a هي مكتفية ذاتيا تماما وليس لديها مثل هذه القضايا مدى الحياة.


وبالنظر إلى الإجابة المقبولة ، سأقدم لك حالة ركنية عند استخدام الفلتر بدلاً من فهم القائمة. سيكون لديك يوم واحد تلبية الوضع القائمة لا يمكن التخلص منه ، وهذا يعني أنك لا يمكن معالجتها مباشرة من خلال فهم القائمة. مثال حقيقي في حالة استخدام pyodbc لقراءة النتائج من قاعدة بيانات ، تكون نتائج fetchAll() من المؤشر قائمة غير قابلة للتلف. في هذه الحالة ، للتلاعب مباشرة في النتائج التي يتم إرجاعها ، يكون الفلتر هو اختيارك بخلاف فهم القائمة. على سبيل المثال:

cursor.execute("SELECT * FROM TABLE1;")
data_from_db = cursor.fetchall()
processed_data = filter(lambda s: 'abc' in s.field1 or s.StartTime >= start_date_time, data_from_db) 

إذا كنت تستخدم الفهم بالقائمة هنا ، فستتلقى الخطأ:

TypeError: نوع قابل للإزالة: 'list'





c++ c++11 lambda