- vừa được xem lúc

C++17: std::invoke

0 0 1

Người đăng: Nguyễn Đặng Triều

Theo Viblo Asia

🚨 Vấn đề Trước C++17: Gọi Hàm Thủ Công

Trong C++ trước phiên bản 17, việc gọi các callable (hàm, lambda, functor, con trỏ hàm, member function, ...) phải xử lý từng trường hợp riêng lẻ, gây rắc rối và khó bảo trì.

🔹 Cách gọi từng kiểu callable trước C++17

Ví dụ sau minh họa cách gọi từng loại callable:

#include <iostream> // Hàm bình thường
void hello() { std::cout << "Hello, World!\n"; } // Functor (Function Object)
struct Functor { void operator()() const { std::cout << "Hello from Functor!\n"; }
}; int main() { // 1️⃣ Gọi hàm bình thường hello(); // 2️⃣ Gọi qua con trỏ hàm void (*funcPtr)() = &hello; (*funcPtr)(); // hoặc funcPtr(); // 3️⃣ Gọi function object (Functor) Functor f; f(); // 4️⃣ Gọi lambda function auto lambda = []() { std::cout << "Hello from Lambda!\n"; }; lambda();
}

🎯 Output:

Hello, World!
Hello, World!
Hello from Functor!
Hello from Lambda!

📌 Vấn đề:

  • Phải gọi từng kiểu callable theo cách riêng lẻ.
  • Code dài dòng, khó tổng quát hóa.

🔹 Tự viết my_invoke (Trước C++17)

Nếu muốn gọi tất cả kiểu callable một cách tổng quát, ta phải tự viết template:

#include <iostream>
#include <type_traits> // Hàm tự định nghĩa giống std::invoke
template <typename Callable, typename... Args>
decltype(auto) my_invoke(Callable&& f, Args&&... args) { return std::forward<Callable>(f)(std::forward<Args>(args)...);
} void hello() { std::cout << "Hello, World!\n"; } struct Functor { void operator()() const { std::cout << "Hello from Functor!\n"; }
}; int main() { auto lambda = []() { std::cout << "Hello from Lambda!\n"; }; my_invoke(hello); // Gọi hàm bình thường my_invoke(Functor{}); // Gọi function object my_invoke(lambda); // Gọi lambda
}

🎯 Output:

Hello, World!
Hello from Functor!
Hello from Lambda!
  • ✅ Tổng quát hóa được mọi callable!
  • ❌ Nhưng chưa hỗ trợ con trỏ tới member function.

🔹 Gọi Con Trỏ Tới Member Function (Trước C++17)

C++ có một kiểu callable đặc biệt là member function của class. Trước C++17, ta phải gọi thủ công như sau:

#include <iostream> class MyClass {
public: void sayHello() const { std::cout << "Hello from MyClass!\n"; }
}; int main() { MyClass obj; void (MyClass::*methodPtr)() const = &MyClass::sayHello; (obj.*methodPtr)(); // Gọi member function qua con trỏ
}

🎯 Output:

Hello from MyClass!

🚨 Vấn đề:

  • Phức tạp khi gọi member function.
  • Không thể dùng my_invoke bên trên vì chưa hỗ trợ member function.

C++17 std::invoke - Giải Pháp Hoàn Hảo!

Từ C++17, std::invoke giúp bạn gọi mọi callable chỉ với một dòng duy nhất! 🎉

#include <iostream>
#include <functional> void hello() { std::cout << "Hello, World!\n"; } struct Functor { void operator()() const { std::cout << "Hello from Functor!\n"; }
}; class MyClass {
public: void sayHello() const { std::cout << "Hello from MyClass!\n"; }
}; int main() { using namespace std; auto lambda = []() { cout << "Hello from Lambda!\n"; }; MyClass obj; invoke(hello); // Gọi hàm bình thường invoke(Functor{}); // Gọi function object invoke(lambda); // Gọi lambda invoke(&MyClass::sayHello, obj); // Gọi member function
}

🎯 Output:

Hello, World!
Hello from Functor!
Hello from Lambda!
Hello from MyClass!
  • ✅ Không cần xử lý từng kiểu callable nữa!
  • ✅ Gọi cả member function dễ dàng!
  • ✅ Code ngắn gọn, tổng quát hóa!

🔹 Mở Rộng std::invoke_result

Nếu bạn cần lấy kiểu trả về của std::invoke, C++17 cung cấp std::invoke_result:

template <typename F, typename... Args>
using InvokeResult = std::invoke_result_t<F, Args...>;

Điều này hữu ích khi viết các template function phức tạp.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Học lập trình game cần những gì?

Lập trình game là làm gì. Các ngôn ngữ các bạn có thể sử dụng để lập trình game : C, C++, C#, Java, Python,... Các bước cơ bản để lập trình game. . Hiển thị: Đã là game thì hiển thị không thể thiếu, lúc đầu các bạn chỉ làm cho phần hiển thị thật đơn giản, các bạn đừng quá chú tâm vào việc làm sao ch

0 0 44

- vừa được xem lúc

[MFC] Http request with winsock2.h

Giới thiệu. Xin chào, trong bài này mình sẽ giới thiệu 1 số lưu ý khi sử dụng thư viện winsock2.h (thư viện window socket) sử dụng trong window app. Đầu tiên, bạn sẽ dễ dàng search được 1 ví dụ cụ thể trên document của winsock2.

0 0 35

- vừa được xem lúc

Design parttern

Builder. 1. Ý tưởng. Builder là một mẫu thiết kế sáng tạo cho phép bạn xây dựng các đối tượng phức tạp theo từng bước.

0 0 32

- vừa được xem lúc

Kỹ thuật viết mã nguồn hiệu quả

Kỹ thuật viết mã nguồn hiệu quả? Hôm nay bài viết này mình không đề cập tới thuật toán, hãy coi như rằng chúng ta đã có thuật toán tốt nhất có thể và bây giờ chúng ta phải làm gì để có thể tăng tính hiệu quả của code. Bài viết này mình sẽ lấy ngôn ngữ lập trình C/C++ để minh họa về các hàm, các thao

0 0 38

- vừa được xem lúc

Singleton Design pattern

Singleton Design pattern. 1. Vấn đề. - Ý tưởng:.

0 0 35

- vừa được xem lúc

So sánh Python và C++

Cuộc tranh luận giữa Python và C ++ là một chủ đề hấp dẫn vì cả hai ngôn ngữ lập trình đều rất khác nhau về cú pháp, tính đơn giản, cách sử dụng và cách tiếp cận tổng thể để lập trình. Vì vậy, mọi người cảm thấy khó khăn khi lựa chọn ngôn ngữ lập trình nào để học.

0 0 40