THƯ VIỆN FUNCTIONAL

Một phần của tài liệu Tổng quan về STL C++ (Trang 54)

III. CONTAINER & ITERATOR 1 Tổng quan về container

4. THƯ VIỆN FUNCTIONAL

#include <functional>

Có nhiều sự mập mờ do từ đồng nghĩa giữa các khái niệm toán học trong cả hai ngôn ngữ tiếng Việt và tiếng Anh, do đó định nghĩa sau chỉ ở mức cố gắng chính xác nhất có thể được:

Số toán tử (operand) của một phép toán (operator), tương ứng là số đối số (argument) của một hàm (function), được gọi là hạng (arity) của phép toán hay hàm đó

Tương tự, số toán tử (operand) của một biểu thức (expression), tương ứng là số đối số (argument) của một đối tượng hàm (functor), được gọi là hạng (arity) của biểu thức hay đối tượng hàm đó

Ví dụ:

-Unary (đơn nguyên, đơn phân, một toán hạng, một ngôi): n! (giai thừa của n) là một unary operator

n! là một unary expression, chỉ bao gồm một unary operator

int giaithua(int n) là một unary function

một object của class giaithua{int operator()(int n)…} là một unary functor -Binary (nhị nguyên, nhị phân, hai toán hạng, hai ngôi):

a + b là một binary expression, chỉ bao gồm một binary operator

int addition(int a,int b) là một binary function

một object của class addition{int operator()(int a,int b)…} là một binary functor -Ternary (tam nguyên, tam phân, ba toán hạng, ba ngôi):

b * b – 4 * a * c là một ternary expression, bao gồm một unary operator và ba binary operator

double delta(double a, double b,double c) là một ternary function

một object của class delta{ double operator()(double a, double b,double c)…} là một ternary functor

Ngoài ra còn có nhiều từ gốc Latin khác như quaternary (bốn toán hạng) quinary (năm toán hạng) … n- ary gọi chung là nhiều toán hạng.

Hạng của predicate tức là hạng của function hay functor mà đóng vai trò predicate. Như ví dụ ở trên, addition là một binary predicate, delta là một ternary predicate

- Cấu trúc unary_function trong thư viện functional

Trong thư viện functional đã định nghĩa sẵn cấu trúc unary_function: template<class Arg,class Result>

struct unary_function {

typedef Arg argument_type; typedef Result result_type; };

unary_function là cấu trúc định nghĩa sẵn cho tất cả unary function và unary functor với Arg là kiểu dữ liệu của đối số và Result là kiểu trả về của hàm có operator()

Chúng ta viết lại lớp IsOdd, định nghĩa nó là một unary_function class IsOdd:public unary_function<int,bool>

{

public:

bool operator()(int n) const

{

return n%2; }

};

- Cấu trúc binary_function trong thư viện functional

Tương tự, trong thư viện functional đã định nghĩa sẵn cấu trúc binary_function template<class Arg1,class Arg2,class Result>

{

typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Result result_type;

};

binary_function là cấu trúc định nghĩa sẵn cho tất cả binary function và binary functor với Arg1 là kiểu dữ liệu của đối số thứ nhất và Arg2 là kiểu dữ liệu của đối số thứ hai và Result là kiểu trả về của hàm có

operator()

Chúng ta viết lại lớp compare, định nghĩa nó là một binary_function class compare:public binary_function<int,int,bool>

{

public:

bool operator()(int i,int j) const

{

return i==j; }

};

Tương tự chúng ta có thể tự viết các cấu trúc ternary_function, quaternary_function, vân vân nếu muốn. Ví dụ dưới đây là một cấu trúc ternary_function tự viết và một lớp được định nghĩa là một

ternary_function

template<class Arg1,class Arg2,class Arg3,class Result> struct ternary_function

{

typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Arg3 third_argument_type; typedef Result result_type;

};

class multiply:public ternary_function<int,float,long,double> {

public:

double operator()(int i,float f,long l) const

{

return i*f*l; }

};

- Ràng buộc (bind) toán hạng cho predicate

Có nhiều hàm chỉ chấp nhận một đối số, nhưng chúng ta lại cần chuyền vào cho nó các predicate là binary predicate như binary function hay binary functor. Trong trường hợp đó chúng ta cần ràng buộc toán hạng cho binary predicate đó để nó trở thành một unary predicate.

Ví dụ chúng ta cần dùng hàm find_if để tìm các phần tử trong một vector thỏa một binary predicate, nhưng find_if lại chỉ chấp nhận unary predicate, khi đó chúng ta cần ràng buộc toán hạng cho binary predicate đó để nó trở thành một unary predicate

binary predicate muốn được ràng buộc toán hạng phải được định nghĩa là một binary_function +Hàm bind1st

Hàm bind1st ràng buộc toán hạng thứ nhất của một binary predicate với một giá trị cho trước để nó trở thành một unary predicate với đối số còn lại của binary predicate ban đầu trở thành đối số của unary predicate kết quả

{

public:

bool operator()(int i,int j) const

{ return i+1==j; } }; int main() { vector<int> v; v.push_back(4);v.push_back(0);v.push_back(1); vector<int>::iterator i=find_if(v.begin(),v.end(),bind1st(compare(),0)); if(i!=v.end()) cout<<i-v.begin(); return 0; }

Trong ví dụ trên, đối số thứ nhất của compare() đã được ràng buộc bằng 0, compare() trở thành một predicate chỉ có một đối số là đối số còn lại của compare() ban đầu, và find_if chỉ việc truyền tham số là iterator trỏ đến các phần tử của v vào đối số này, quá trình chạy vòng lặp diễn ra giống như sau

compare()(0,4) //phép so sánh 0 + 1 == 4 trả về false compare()(0,0) //phép so sánh 0 + 1 == 0 trả về false compare()(0,1) //phép so sánh 0 + 1 == 1 trả về true +Hàm bind2nd

Hàm bind2nd ràng buộc toán hạng thứ hai của một binary predicate với một giá trị cho trước để nó trở thành một unary predicate với đối số còn lại của binary predicate ban đầu trở thành đối số của unary predicate kết quả

class compare:public binary_function<int,int,bool> {

public:

bool operator()(int i,int j) const

{ return i+1==j; } }; int main() { vector<int> v; v.push_back(4);v.push_back(0);v.push_back(1); vector<int>::iterator i=find_if(v.begin(),v.end(),bind2nd(compare(),1)); if(i!=v.end()) cout<<i-v.begin(); return 0; }

Trong ví dụ trên, đối số thứ hai của compare() đã được ràng buộc bằng 1, compare() trở thành một predicate chỉ có một đối số là đối số còn lại của compare() ban đầu, và find_if chỉ việc truyền tham số là iterator trỏ đến các phần tử của v vào đối số này, quá trình chạy vòng lặp diễn ra giống như sau

compare()(4,1) //phép so sánh 4 + 1 == 1 trả về false compare()(0,1) //phép so sánh 0 + 1 == 1 trả về true

compare()(1,1) //phép so sánh 1 + 1 == 1 trả về false (thực ra không có phép so sánh này, hàm

đã trả về iterator rồi)

b)Các hàm toán học cơ bản của thư viện functional

Bao gồm cộng (plus) trừ (minus) nhân (multiplies) chia (divides) chia lấy dư (modulus) đổi dấu (negate) Các hàm này rất đơn giản, ví dụ:

int a[]={1,-2,3}; transform(a,a+3,a,negate<int>()); for_each(a,a+3,Output<int>()); plus: int a[]={1,2,3,4,5}; int b[]={6,7}; int c[5]; transform(a,a+5,b,c,plus<int>());

Ở vd trên có một điều đáng chú ý, bạn tự tìm xem modulus:

int a[]={1,2,3,4,5}; int b[]={2,2,2,2,2}; int c[5];

transform(a,a+5,b,c,modulus<int>());

Cái ví dụ hàm modulus này hơi … kì kì. Modulus là một binary function, giả sử bây giờ chúng ta muốn các phần tử của a luôn modulus cho 2 thì làm thế nào ? Phải ràng buộc toán hạng cho modulus để nó trở thành một unary function thôi:

int a[]={1,2,3,4,5}; int b[5];

transform(a,a+5,b,bind2nd(modulus<int>(),2));

Các hàm so sánh bao gồm equal_to (==) not_equal_to (!=) greater (>) less (<) greater_equal (>=) less_equal(<=) logical_and (&&) logical_or (||) logical_not (!)

Các hàm này cách dùng y như nhau, lấy một ví dụ hàm greater: int a[]={3,2,5,1,4};

sort(a,a+5,greater<int>()); for_each(a,a+5,Output<int>());

Giả sử ta muốn dùng hàm count_if với hàm greater, trả về số phần tử nhỏ hơn 3 chẳng hạn. Ta làm thế nào ? greater là một binary function, lại phải ràng buộc toán hạng cho nó với đối số thứ nhất là 3 rồi

int a[]={3,2,5,1,4};

cout<<(int)count_if(a,a+5,bind1st(greater<int>(),3)); for_each(a,a+5,Output<int>());

Một phần của tài liệu Tổng quan về STL C++ (Trang 54)