0

So sánh std::function và std::invoke

Trong C++, cả std::functionstd::invoke đều dùng để làm việc với các đối tượng callable (hàm, lambda, functor, con trỏ hàm), nhưng chúng phục vụ hai mục đích khác nhau:

  • std::function: Lưu trữ callable để gọi sau.
  • std::invoke: Gọi callable ngay tại thời điểm sử dụng.

1. Signature là gì?

Trong C++, signature của hàm (định danh hàm) bao gồm:

  • Kiểu trả về (Return Type): Kiểu dữ liệu mà hàm trả về.
  • Kiểu tham số (Parameter Types): Kiểu dữ liệu của từng tham số hàm nhận vào.

Ví dụ:

int add(int a, int b) {
    return a + b;
}

Signature của hàm add() là:

  • Kiểu trả về: int
  • Kiểu tham số: (int, int)

2. std::function - Lưu trữ callable

std::function là một template class cho phép lưu trữ và gọi các callable có cùng signature.

Cách hoạt động:

  • Khi tạo std::function, ta phải xác định signature của callable.
  • Sau đó, callable nào khớp với signature đó có thể được gán vào.
  • Để gọi callable, ta dùng operator().

Ví dụ:

#include <iostream>
#include <functional>

int add(int a, int b) { return a + b; }
auto multiply = [](int a, int b) { return a * b; };

int main() {
    std::function<int(int, int)> operation;

    operation = add;
    std::cout << "Kết quả cộng: " << operation(5, 3) << std::endl;

    operation = multiply;
    std::cout << "Kết quả nhân: " << operation(5, 3) << std::endl;

    return 0;
}

Khi nào nên dùng std::function?

  • ✅ Khi cần lưu trữ callable để gọi sau.
  • ✅ Khi muốn truyền callable vào hàm mà không dùng template.
  • ✅ Khi cần thay đổi callable linh hoạt.

3. std::invoke - Gọi callable ngay lập tức

std::invoke là một template hàm giúp gọi callable một cách tổng quát.

Cách hoạt động:

  • Truyền vào callable và các tham số.
  • std::invoke tự động gọi callable đó.

Ví dụ:

#include <iostream>
#include <functional>

int subtract(int a, int b) { return a - b; }
struct Divider {
    double operator()(double a, double b) const { return a / b; }
};

int main() {
    Divider divide;

    std::cout << "Kết quả trừ: " << std::invoke(subtract, 10, 4) << std::endl;
    std::cout << "Kết quả chia: " << std::invoke(divide, 10.0, 2.0) << std::endl;

    return 0;
}

Khi nào nên dùng std::invoke?

  • ✅ Khi muốn gọi callable ngay lập tức.
  • ✅ Khi viết code tổng quát (generic programming) mà không biết callable là kiểu gì.
  • ✅ Khi gọi hàm thành viên của class một cách tự động.

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí