std::function
จัดเก็บสิ่งที่เรียกใช้งานได้ทุกชนิด
std::function เป็นบทเรียน C++ Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 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” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C++ Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C++ Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “std::function”
จัดเก็บสิ่งที่เรียกใช้งานได้ทุกชนิด คุณปฏิบัติ C++ Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C++ Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C++ Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “std::function” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C++ Academy นี้ได้ไหม
ได้ บทเรียน C++ Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ