0Pricing
C++ Academy · บทเรียน

การเลือกสิ่งที่เรียกใช้งานได้

แลมบ์ดา เทียบกับ bind เทียบกับพอยน์เตอร์

การเลือกสิ่งที่เรียกใช้งานได้ เป็นบทเรียน C++ Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C++ Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C++ Academy มีบทเรียนทั้งหมด 4 บทเรียน

ชุดเครื่องมือสำหรับสิ่งที่เรียกใช้งานได้

C++ มีหลายวิธีสำหรับส่งต่อพฤติกรรม: พอยน์เตอร์ฟังก์ชัน แลมบ์ดา ฟังก์เตอร์ std::bind และ std::function แต่ละแบบเหมาะกับความต้องการที่แตกต่างกัน

  • การแลกเปลี่ยนระหว่างความเร็วกับความยืดหยุ่นเป็นสิ่งที่พบได้ทั่วไป
  • ความอ่านเข้าใจง่ายก็สำคัญเช่นกัน
#include <iostream>

int twice(int x) { return x * 2; }

int main() {
    int (*fp)(int) = twice;
    auto lam = [](int x) { return x * 2; };
    std::cout << fp(5) << ' ' << lam(5) << '\n';
    return 0;
}

เมื่อใดควรใช้พอยน์เตอร์ฟังก์ชัน

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

#include <iostream>

void logMsg(const char* m) { std::cout << "LOG: " << m << '\n'; }

int main() {
    void (*handler)(const char*) = logMsg;
    handler("started");
    return 0;
}

เมื่อใดควรใช้แลมบ์ดา

แลมบ์ดาเป็นตัวเลือกเริ่มต้นที่ทันสมัย: เขียนได้กระชับ จับสถานะได้ และคอมไพเลอร์สามารถแทรกโค้ดให้มีประสิทธิภาพได้ดีในแม่แบบและอัลกอริทึม

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5};
    std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
    for (int x : v) std::cout << x << ' ';
    std::cout << '\n';
    return 0;
}

การจับสถานะในแลมบ์ดา

แลมบ์ดาสามารถจับตัวแปรรอบข้างได้ ซึ่งเป็นสิ่งที่พอยน์เตอร์ฟังก์ชันทำไม่ได้ จึงเหมาะอย่างยิ่งสำหรับการเรียกกลับที่ต้องอาศัยบริบท

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    int threshold = 3;
    std::vector<int> v = {1, 2, 3, 4, 5};
    int c = std::count_if(v.begin(), v.end(), [threshold](int x) { return x > threshold; });
    std::cout << c << '\n';
    return 0;
}

เมื่อใดควรใช้ฟังก์เตอร์

ฟังก์เตอร์ (struct ที่มี operator()) เหมาะกับการดำเนินการที่นำกลับมาใช้ใหม่ได้และมีชื่อเรียก ซึ่งอาจเก็บการตั้งค่าและใช้ได้ในหลายตำแหน่ง

#include <iostream>
#include <vector>
#include <algorithm>

struct AboveThreshold {
    int limit;
    bool operator()(int x) const { return x > limit; }
};

int main() {
    std::vector<int> v = {1, 5, 2, 8};
    std::cout << std::count_if(v.begin(), v.end(), AboveThreshold{4}) << '\n';
    return 0;
}

แลมบ์ดากับการผูก

ทั้งสองแบบสามารถเติมอาร์กิวเมนต์ล่วงหน้าได้ โดยทั่วไปเวอร์ชันแลมบ์ดาจะอ่านเข้าใจได้ง่ายกว่าและปรับปรุงประสิทธิภาพโดยคอมไพเลอร์ได้ง่ายกว่า ดังนั้นจึงควรเลือกใช้แทน std::bind

#include <iostream>

int power(int base, int exp) {
    int r = 1;
    for (int i = 0; i < exp; ++i) r *= base;
    return r;
}

int main() {
    auto square = [](int x) { return power(x, 2); };
    std::cout << square(6) << '\n';
    return 0;
}

เมื่อใดควรใช้ std::function

ใช้ std::function เมื่อคุณต้องเก็บสิ่งที่เรียกใช้งานได้ซึ่งไม่ทราบชนิดที่เป็นรูปธรรม เช่น ในสมาชิกของคลาสหรือคอนเทนเนอร์

#include <iostream>
#include <functional>
#include <vector>

int main() {
    std::vector<std::function<int(int)>> pipeline;
    pipeline.push_back([](int x) { return x + 1; });
    pipeline.push_back([](int x) { return x * 3; });
    int v = 2;
    for (auto& f : pipeline) v = f(v);
    std::cout << v << '\n';
    return 0;
}

แม่แบบหลีกเลี่ยงค่าใช้จ่ายเพิ่มเติม

หากฟังก์ชันต้องการเพียงรับสิ่งที่เรียกใช้งานได้ (ไม่ได้เก็บไว้) พารามิเตอร์แม่แบบจะรักษาความเร็วเต็มที่ด้วยการหลีกเลี่ยงการลบชนิด

#include <iostream>

template <typename F>
int applyTwice(int x, F f) { return f(f(x)); }

int main() {
    std::cout << applyTwice(3, [](int n) { return n + 10; }) << '\n';
    return 0;
}

การจัดอันดับประสิทธิภาพ

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

#include <iostream>
#include <functional>

int main() {
    auto fast = [](int x) { return x + 1; };
    std::function<int(int)> flexible = fast;
    std::cout << fast(1) << ' ' << flexible(1) << '\n';
    return 0;
}

แนวทางการตัดสินใจ

แนวทางอย่างรวดเร็ว:

  • ต้องการเก็บสิ่งที่เรียกใช้งานได้ทุกชนิดใช่หรือไม่ ใช้ std::function
  • เพียงรับสิ่งที่เรียกใช้งานได้ในฟังก์ชันทั่วไปใช่หรือไม่ ใช้พารามิเตอร์แม่แบบ
  • ต้องการพฤติกรรมที่เขียนไว้ในบรรทัดและมีสถานะใช่หรือไม่ ใช้แลมบ์ดา
  • ต้องการส่วนเชื่อมต่อกับ C หรือสิ่งที่ไม่มีสถานะใช่หรือไม่ ใช้พอยน์เตอร์ฟังก์ชัน
#include <iostream>
#include <functional>

void runStored(const std::function<void()>& cb) { cb(); }

template <typename F>
void runGeneric(F f) { f(); }

int main() {
    runStored([] { std::cout << "stored\n"; });
    runGeneric([] { std::cout << "generic\n"; });
    return 0;
}

นำทุกอย่างมารวมกัน

ระบบเหตุการณ์ขนาดเล็กอาจรับตัวจัดการแบบทั่วไป แต่เก็บตัวจัดการเหล่านั้นไว้ใน std::function เพื่อให้เรียกใช้ได้ภายหลัง

#include <iostream>
#include <functional>
#include <vector>

struct Dispatcher {
    std::vector<std::function<void(int)>> handlers;
    template <typename F> void on(F f) { handlers.emplace_back(f); }
    void fire(int e) { for (auto& h : handlers) h(e); }
};

int main() {
    Dispatcher d;
    d.on([](int e) { std::cout << "got " << e << '\n'; });
    d.fire(7);
    return 0;
}

ตรวจสอบอย่างรวดเร็ว

ทดสอบความเข้าใจของคุณเกี่ยวกับการเลือกสิ่งที่เรียกใช้งานได้

สรุปทบทวน

คุณได้เรียนรู้วิธีเลือกสิ่งที่เรียกใช้งานได้:

  • พอยน์เตอร์ฟังก์ชันสำหรับการเรียกกลับที่ไม่มีสถานะและเข้ากันได้กับ C
  • แลมบ์ดาเป็นตัวเลือกเริ่มต้นสำหรับพฤติกรรมที่เขียนไว้ในบรรทัดและมีสถานะ
  • ฟังก์เตอร์สำหรับการดำเนินการที่มีชื่อและนำกลับมาใช้ใหม่ได้
  • พารามิเตอร์แม่แบบเมื่อรับสิ่งที่เรียกใช้งานได้เพียงอย่างเดียว (เร็วที่สุด)
  • std::functionเมื่อคุณต้องเก็บสิ่งที่เรียกใช้งานได้ซึ่งไม่ทราบชนิด

หลักสูตรออบเจ็กต์ฟังก์ชันและ std::bind จบลงเพียงเท่านี้

คำถามที่พบบ่อย

บทเรียน “การเลือกสิ่งที่เรียกใช้งานได้” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การเลือกสิ่งที่เรียกใช้งานได้” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C++ Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C++ Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การเลือกสิ่งที่เรียกใช้งานได้”

แลมบ์ดา เทียบกับ bind เทียบกับพอยน์เตอร์ คุณปฏิบัติ C++ Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C++ Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C++ Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การเลือกสิ่งที่เรียกใช้งานได้” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C++ Academy นี้ได้ไหม

ได้ บทเรียน C++ Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. พอยน์เตอร์ฟังก์ชัน
  2. std::function
  3. std::bind
  4. การเลือกสิ่งที่เรียกใช้งานได้
← กลับไปที่ C++ Academy