std::function
خزّن أي كائن قابل للاستدعاء
std::function درس مجاني في C++ Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C++ Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C++ Academy 4 دروس في المجموع.
ما هو std::function؟
إن std::function غلاف لمحو النوع، ويمكنه احتواء أي كيان قابل للاستدعاء يطابق توقيعًا معينًا، مثل الدوال الحرة ولامبدا وكائنات الدوال والتعبيرات المربوطة.
- يُصرَّح به باستخدام التوقيع المستهدف.
- يوجد في
<functional>.
#include <iostream>
#include <functional>
int add(int a, int b) { return a + b; }
int main() {
std::function<int(int, int)> f = add;
std::cout << f(2, 3) << '\n';
return 0;
}تخزين لامبدا
على خلاف مؤشر الدالة الخام، يخزّن std::function لامبدا بسهولة، حتى إن كانت تلتقط متغيرات.
#include <iostream>
#include <functional>
int main() {
int offset = 10;
std::function<int(int)> f = [offset](int x) { return x + offset; };
std::cout << f(5) << '\n';
return 0;
}تخزين كائن دالة
إن كائن الدالة هو كائن له operator(). ويمكن لـ std::function تغليفه واستدعاء معامل التشغيل الخاص به عند استدعائه.
#include <iostream>
#include <functional>
struct Multiplier {
int factor;
int operator()(int x) const { return x * factor; }
};
int main() {
std::function<int(int)> f = Multiplier{3};
std::cout << f(4) << '\n';
return 0;
}إعادة تعيين الهدف
يمكن لمتغير واحد من نوع std::function أن يحتفظ بكيانات قابلة للاستدعاء مختلفة طوال فترة وجوده، وهو أمر مفيد لتبديل السلوك أثناء التشغيل.
#include <iostream>
#include <functional>
int main() {
std::function<int(int)> f = [](int x) { return x + 1; };
std::cout << f(10) << '\n';
f = [](int x) { return x * x; };
std::cout << f(10) << '\n';
return 0;
}std::function فارغ
لا يحتوي كائن std::function المُنشأ افتراضيًا على شيء. ويؤدي استدعاؤه إلى رمي std::bad_function_call، لذا اختبره أولًا.
#include <iostream>
#include <functional>
int main() {
std::function<void()> f;
if (f) {
f();
} else {
std::cout << "empty\n";
}
return 0;
}كوسيط
يمكن للدوال قبول وسيط من نوع std::function لاستقبال أي كيان قابل للاستدعاء يطابق التوقيع، مما يجعل واجهات برمجة التطبيقات مرنة.
#include <iostream>
#include <functional>
void repeat(int n, const std::function<void(int)>& action) {
for (int i = 0; i < n; ++i) action(i);
}
int main() {
repeat(3, [](int i) { std::cout << "step " << i << '\n'; });
return 0;
}تخزين دوال ردّ الاتصال
من الاستخدامات الشائعة الاحتفاظ بدالة ردّ اتصال في عضو من أعضاء الصنف، بحيث يمكن استدعاؤها لاحقًا عند وقوع حدث.
#include <iostream>
#include <functional>
struct Button {
std::function<void()> onClick;
void click() { if (onClick) onClick(); }
};
int main() {
Button b;
b.onClick = [] { std::cout << "clicked!\n"; };
b.click();
return 0;
}متجه من الكيانات القابلة للاستدعاء
بما أنها تشترك في نوع واحد، يمكن أن تتواجد كيانات قابلة للاستدعاء مختلفة معًا في حاوية وأن تُستدعى بالتتابع.
#include <iostream>
#include <functional>
#include <vector>
int inc(int x) { return x + 1; }
int main() {
std::vector<std::function<int(int)>> ops;
ops.push_back(inc);
ops.push_back([](int x) { return x * 2; });
for (auto& op : ops) std::cout << op(10) << ' ';
std::cout << '\n';
return 0;
}تكلفة محو النوع
قد يخصص std::function ذاكرة ويضيف استدعاءً غير مباشر، لذا فهو أبطأ قليلًا من الاستدعاء المباشر أو الكيان القابل للاستدعاء المعرّف باستخدام قالب. استخدمه عندما تحتاج إلى تخزين موحّد.
#include <iostream>
#include <functional>
int main() {
std::function<int()> f = [] { return 42; };
int total = 0;
for (int i = 0; i < 5; ++i) total += f();
std::cout << total << '\n';
return 0;
}إرجاع std::function
يمكن لدالة مصنع إنشاء كيان قابل للاستدعاء مُهيأ وإرجاعه، مما يتيح للمستدعين الحصول على سلوك مخصص.
#include <iostream>
#include <functional>
std::function<int(int)> adder(int n) {
return [n](int x) { return x + n; };
}
int main() {
auto add5 = adder(5);
std::cout << add5(10) << '\n';
return 0;
}المقارنة مع مؤشرات الدوال
إن std::function أكثر مرونة من مؤشر الدالة لأنه يخزّن الحالة، لكن هذه المرونة تكلّف قليلًا من الأداء وقد تتطلب تخصيصًا للذاكرة.
#include <iostream>
#include <functional>
int main() {
int base = 7;
std::function<int(int)> stateful = [base](int x) { return x + base; };
std::cout << "Stateful result: " << stateful(3) << '\n';
return 0;
}اختبار سريع
اختبر مدى فهمك لـ std::function.
مراجعة
لقد تعلمت أن std::function:
- يغلّف أي كيان قابل للاستدعاء يطابق توقيعه، بما في ذلك لامبدا ذات الحالة وكائنات الدوال
- يمكن إعادة تعيينه وتخزينه في حاويات وإرجاعه من دوال المصنع
- يرمي
bad_function_callعندما يكون فارغًا - يضيف عبئًا إضافيًا قليلًا بسبب محو النوع
بعد ذلك ستستخدم std::bind لملء وسائط الكيانات القابلة للاستدعاء مسبقًا.
الأسئلة الشائعة
هل درس «std::function» مجاني؟
نعم — نص درس «std::function» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C++ Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C++ Academy 4 دروس في المجموع.
ماذا ستتعلم في «std::function»؟
خزّن أي كائن قابل للاستدعاء تتمرن على C++ Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ C++ Academy؟
لا تُشترط خبرة سابقة. C++ Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «std::function»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس C++ Academy هذا؟
نعم. كل درس في C++ Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.