سؤال

من الضروري بالنسبة لي الاستخدام std::function لكني لا أعرف معنى بناء الجملة التالي.

std::function<void()> f_name = []() { FNAME(); };

ما هو هدف استخدام std::function؟ هل هو جعل مؤشر إلى وظيفة؟

هل كانت مفيدة؟

المحلول

std::function هو كائن محو النوع. هذا يعني أنه يمحو تفاصيل كيفية حدوث بعض العمليات ، ويوفر واجهة وقت تشغيل موحدة لهم. إلى عن على std::function, ، الابتدائي1 العمليات هي النسخ/الحركة ، والتدمير ، و "الاحتجاج" مع operator() - "وظيفة مثل مشغل المكالمات".

في اللغة الإنجليزية الأقل هزيمة ، هذا يعني ذلك std::function يمكن أن تحتوي على أي كائن تقريبًا يعمل مثل مؤشر الوظيفة في كيفية تسميته.

يذهب التوقيع الذي يدعمه داخل أقواس الزاوية: std::function<void()> يأخذ الصفر الحجج ولا يعيد شيئًا. std::function< double( int, int ) > يأخذ اثنين int الحجج والعودة double. على العموم، std::function يدعم تخزين أي كائن يشبه الوظيفة يمكن تحويل وسيطه من قائمة الوسيطة الخاصة به ، ويمكن تحويل قيمة الإرجاع إلى قيمة الإرجاع الخاصة به.

من المهم معرفة ذلك std::function و Lambdas مختلفة ، إذا كانت متوافقة ، الوحوش.

الجزء التالي من الخط هو لامدا. هذا بناء جملة جديد في C ++ 11 لإضافة القدرة على كتابة كائنات بسيطة تشبه الوظائف-الكائنات التي يمكن التذرع بها (). يمكن محو هذه الكائنات وتخزينها في أ std::function على حساب بعض وقت التشغيل النفقات العامة.

[](){ code } على وجه الخصوص هو لامدا بسيط حقا. وهو يتوافق مع هذا:

struct some_anonymous_type {
  some_anonymous_type() {}
  void operator()const{
    code
  }
};

مثيل لنوع الوظيفة الزائفة البسيطة أعلاه. يتم "اختراع" فئة فعلية مثل ما سبق "تم اختراعها" من قبل برنامج التحويل البرمجي ، مع تطبيق فريد محدد (غالبًا بما في ذلك الرموز التي لا يمكن أن تحتوي عليها أي نوع محدد من قبل المستخدم) (لا أعرف ما إذا كان من الممكن أن تتمكن من اتباع المعيار دون الاختراع مثل هذا الفصل ، ولكن كل مترجم أعرفه في الواقع يخلق الفصل).

يشبه بناء جملة Lambda الكامل:

[ capture_list ]( argument_list )
-> return_type optional_mutable
{
  code
}

ولكن يمكن حذف العديد من الأجزاء أو تركها فارغة. يتوافق Capture_List مع كل من مُنشئ النوع المجهول الناتج ومتغيراته الأعضاء ، و engument_list وسيطات operator(), ، ونوع الإرجاع نوع الإرجاع. يتم أيضًا استدعاء مُنشئ مثيل Lambda بطريقة سحرية عند إنشاء المثيل باستخدام Capture_List.

[ capture_list ]( argument_list ) -> return_type { code }

يصبح أساسا

struct some_anonymous_type {
  // capture_list turned into member variables
  some_anonymous_type( /* capture_list turned into arguments */ ):
    /* member variables initialized */
  {}
  return_type operator()( argument_list ) const {
    code
  }
};

لاحظ ذلك في تمت إضافة حجج القالب إلى Lambdas ، وهذا غير مغطى أعلاه.

[]<typename T>( std::vector<T> const& v ) { return v.size(); }

1 بالإضافة إلى ذلك ، يتم تخزين RTTI (TypeID) ، ويتم تضمين تشغيل النوع من الأرجوانيين.

نصائح أخرى

لنفصل الخط:

STD :: وظيفة

هذا إعلان لوظيفة لا تأخذ أي معلمات ، وعدم إرجاع أي قيمة. إذا عادت الوظيفة int, ، انها تبدو مثل هذا:

std::function<int()>

وبالمثل ، إذا استغرق الأمر معلمة int أيضًا:

std::function<int(int)>

أظن أن الارتباك الرئيسي هو الجزء التالي.

[]() { FNAME(); };

ال [] يسمى الجزء أ جملة التقاط. هنا تضع المتغيرات المحلية في إعلان Lambda الخاص بك ، وتريد أن تكون متاحًا داخل وظيفة لامدا نفسها. هذا يقول "لا أريد أن يتم القبض على أي شيء". إذا كان هذا ضمن تعريف الفصل وأردت أن يكون الفصل متاحًا لـ Lambda ، فيمكنك القيام بذلك:

[this]() { FNAME(); };

الجزء التالي ، هو المعلمات التي يتم تمريرها إلى Lambda ، بالضبط كما لو كانت وظيفة منتظمة. كما ذكر آنفا، std::function<void()> هو توقيع يشير إلى طريقة لا تأخذ أي معلمات ، لذلك هذا فارغ أيضا.

بقية ذلك هو جسم Lambda نفسه ، كما لو كانت وظيفة منتظمة ، والتي يمكننا أن نرى فقط تستدعي الوظيفة FNAME.

مثال آخر

دعنا نقول أن لديك التوقيع التالي ، وهذا هو لشيء يمكن أن يلخص رقمين.

std::function<int(int, int)> sumFunc;

يمكننا الآن إعلان Lambda وبالتالي:

sumFunc = [](int a, int b) { return a + b; };

لست متأكدًا مما إذا كنت تستخدم MSVC ، ولكن إليك رابط على أي حال إلى بناء جملة تعبير Lamda:

http://msdn.microsoft.com/en-us/library/dd293603.aspx

لا يمكن تعيين Lambdas مع التقاطات (Lambdas الحكومية) لبعضها البعض لأن لديهم أنواع فريدة ، حتى لو كانت تبدو كما هي بالضبط. لتكون قادرة على تخزين والمرور حول Lambdas مع التقاطات ، يمكننا استخدام "STD :: وظيفة"لعقد كائن دالة تم إنشاؤه بواسطة تعبير lambda. بشكل أساسي"STD :: وظيفة"هو ، لتكون قادرًا على تعيين وظائف Lambda مع هياكل محتوى مختلفة لكائن دالة Lambda.

إكسب:

auto func = [](int a){
 cout << "a:" << a << endl;
};
func(40);
//
int x = 10;
func = [x](int a){ //ATTENTION(ERROR!): assigning a new structure to the same object
 cout << "x:" << x << ",a:" << a << endl;
};
func(2);

لذلك سيكون الاستخدام أعلاه غير صحيح. ولكن إذا حددنا كائن وظيفة مع "STD :: Function":

auto func = std::function<void(int)>{};
func = [](int a){
  cout << "a:" << a << endl;
};
func(40);
//
int x = 10;
func = [x](int a){ //CORRECT. because of std::function
  //...
}; 

int y = 11;
func = [x,y](int a){ //CORRECT
 //...
}; 
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top