Modern C++: Functors

Manh

March 11, 2016

C++

1. Functor là gì?

Nếu như là một fan trung thành của C++ STL (Standard Template Library), bạn sẽ bắt gặp functor rất nhiều.

Ví dụ trong đoạn code sau:

#include <iostream>
#include <vector>
#include <algorithm>
 
void increment(int& i) {
    ++i;
    std::cout << i << ' ';
}
 
int main() {
    std::vector<int> v = {1, 2, 3, 4, 5, 6};
 
    void (*fun_ptr) (int&) = &increment;
 
    std::for_each(v.begin(), v.end(), increment);
    std::cout << std::endl;
 
    std::for_each(v.begin(), v.end(), fun_ptr);
    std::cout << std::endl;
 
    return 0;
}

Nếu bạn chưa dùng for_each bao giờ, bạn có thể tham khảo tài liệu về nó ở link

Hàm for_each và cũng như rất nhiều hàm trong thư viện STL (std::sort, std::count_if, std::remove_if,…) đều là những hàm nhận functor – tất nhiên functor là một danh từ chung, ở trường hợp cụ thể của mỗi hàm thì tên gọi nó lại khác nhau, ví dụ với sort thì có thể gọi là Comparator, count_if, remove_if thì lại là Predicate).

Functor – đơn giản là một thứ gì đó thực thi công việc giúp bạn.

Ở đoạn code phía trên, functor có thể là một hàm tự do, hoặc có thể là một function pointer (biến trỏ hàm).

Thực tế rằng những hàm này đã wrap các function/function pointer mà bạn truyền vào, thành một Function Object và gọi function object đó khi cần thiết.

Vậy nên chính xác hơn, functor là một function object.

Function object được sử dụng rất nhiều (hầu hết) trong thư viện STL C++, và nên viết functor để sử dụng các thuật toán, các chức năng của STL một cách hiệu quả hơn theo ý muốn.

2. Function Object

Cũng là đoạn code ở như trên, nhưng mình sẽ dùng một function object.

#include <iostream>
#include <vector>
#include <algorithm>
 
class Incrementor {
public:
    void operator()(int& i) {
        ++i;
        std::cout << i << ' ';
    }
};
 
int main() {
    std::vector<int> v = {1, 2, 3, 4, 5, 6};
 
    Incrementor in;
 
    std::for_each(v.begin(), v.end(), in);
    std::cout << std::endl;
 
    return 0;
}

Mình đã tạo ra một object, và truyền nó vào for_each như một functor.

Function object là một object được định nghĩa toán tử (), và bạn có thể sử dụng nó như một hàm.

Code:

Incrementor in;
in(1);

hoặc

std::for_each(v.begin(), v.end(), Incrementor());

3. Vậy sử dụng functor khác gì một hàm/con trỏ hàm?

Trạng thái: Functor không phải một hàm, nó là một object, nên bạn có thể tùy biến theo ý mình, ví dụ viết ra một functor có khả năng config để thực thi một công việc phức tạp. Khác với một hàm thông thường rằng nó luôn cho ra kết quả với input tương ứng, luôn thực thi từ đầu đến cuối. Với functor bạn sẽ có thể tạo ra các thực thi linh hoạt hơn.

OOP tốt hơn: thiết kế các solution theo hướng sử dụng functor sẽ giúp code của bạn được tổ chức tốt hơn, logic hơn.

Tốc độ: Trình dịch sẽ cố gắng inline functor của bạn, còn với function pointer thì không.

Comments

comments

Related Posts

Hãy dừng việc sử dụng fflush(stdin) để xóa dòng nhập

Manh

March 16, 2016

C++

1. Hiện thực – Lập trình C được giảng dạy ở Việt Nam một cách rất “hỗn tạp” – Vì chỉ được coi là một môn học “nhập môn” nên giảng dạy khá “cẩu thả” – C không xứng đáng là để dạy nhập môn, hãy dạy nó chuyên sâu: Vì sao lại khiến một […]

Read More

Lập trình giao diện console: NCurses Form

Manh

December 22, 2015

C++

Trong bài hôm nay chúng ta sẽ add thêm hành động vào Menu, khi được lựa chọn, chương trình sẽ tạo ra một form nhập dữ liệu.   1. Color Attributes Chúng ta đã biết rằng một ứng dụng NCurses có thể sử dụng màu hoặc không. Vậy có thể thay đổi các màu hiển […]

Read More