In addition to the custom function object, the standard library provides us with a series of ready-made function objects, such as common mathematics, logical operation, etc. For example:negate<type> (),plus<type> (),minus<type> (),multiplies<type> (),divides<type> (), Modulus<type> (),equal_to<type>,greater<type> (),less<type> (),logical_not<type> (), Logical_and<type> (), and so on.
The last important concept about function objects is "function adapters." function adapter, which is essentially a function object. This function object completes certain functions by combining one or more function objects or specific data into certain rules. The standard library provides us with several function adapters, such as: to return the adapter via bind1st and bind2nd two wrapper functions, each with two parameters, two function objects and a numeric value, and the adapter automatically assigns the value to the 1th (bind1st) of the function object. or a 2nd (bind2nd) parameter, and returns a Unary function object. For example, the following statement:
Find_if (Vec.begin (), Vec.end (), bind2nd (Modulus<int> (), 2));
Modulus<int> () Initializes a two-dollar function object, bind2nd function gives ' 2 ' its second argument, and returns a Unary function object that determines whether an integer is an even number. The purpose of this statement is to find the first even number in the container VEC.
Note: Don't mistake bind1st and bind2nd for function adapters, they are just two ordinary wrapper function templates that return the real function adapter. The corresponding function object types are binder1st and binder2nd respectively. The two function templates implement the following:
Template<typename operation,typename t>
binder1st bind1st (const Operation &OP, const T &t)
{ Return
binder1st<operation> (op,typename operation::first_argument_type (t));
}
Template<typename operation,typename t>
binder1st bind2nd (const Operation &OP, const T &t)
{ Return
binder2nd<operation> (op,typename operation::second_argument_type (t));
}
No matter what the details, we'll talk about it later. We focus only on the implementation of the function, and it's easy to see that the return is the object of Class binder1st<operation> and binder2nd<operation>, which is what we call a function adapter.
In addition to these two function adapters, the standard library also defines two "take-back", which can be obtained by invoking the auxiliary functions not1 and Not2, that is, unary_negate<type> and binary_negate<type>. In addition, the wrapper function template Mem_func_ref returned adapters are used to automatically invoke the object's member functions, details and other adapters can be viewed on the C + + reference website.
A function adapter is a powerful tool in C + + that allows us to generate meaningful expressions for multiple function objects to be arbitrarily grouped according to their needs. This method is called "function composition". For example, for functions f (x), g (x), H (x,y), they are combined to generate a complex function such as f (g (x)), G (f (x)), H (f (x), g (x)), and so on. Here f,g corresponds to a unary function object, h corresponds to two-element function object, the combination function can be considered as a function adapter.
Unfortunately, the standard library does not provide us with too many adapters. Therefore, to make good use of it, we also need to define ourselves. We already know that customizing a function object is a very easy thing to do, but it takes some extra work to get a function object to be grouped in an adapter. To facilitate the creation of function objects that can be used in adapters, the standard library defines two useful constructs, namely:
Template <class arg, class result>
struct unary_function
{
typedef arg argument_type;
typedef result RESULT_TYPE;
Template <class Arg1, class Arg2, class result>
struct binary_function
{
typedef Arg1 FIRST_ARGUMENT_ type;
typedef ARG2 SECOND_ARGUMENT_TYPE;
typedef result RESULT_TYPE;
These two structures define several types of members to represent the types of function object arguments and return values. Where unary_function represents a unary function object, Binary_function represents a two-tuple function object. You can use it in a function adapter by allowing our custom function object to inherit the corresponding structure. The function object of the standard library is precisely this design, we take the adapter binder1st as an example to illustrate, the class binder1st is as follows:
Template<class operation>
class Binder1st:public Unary_function<typename Operation::second_argument_ Type, typename operation::return_type>
{public
:
binder1st (const Operation &OP, Const TypeName Operation::first_argument_type &arg): Operation (OP), arg_1st (ARG) {}
typename Operation::return_type Operator () (const typename Operation::second_argument_type &arg_2nd) const
{return
Operation (arg_1st, arg_2nd);
}
Private:
Operation Operation;
TypeName Operation::first_argument_type arg_1st;
The adapter calls the constructor by accepting a two-dollar function object (Operation) and a value (ARG) of the first parameter type of the two-function object. In its overloaded "()" operator function, only one parameter is accepted, corresponding to the argument_type of its base class unary_function, and returns the Return_type of type unary_function. TypeName Operation::first_argument, TypeName Operation::second_argument_type and TypeName Operation::result_ are frequently used in class definitions Type, fully explain the requirements of the operation, as long as operation inherited Binary_function can. Let's illustrate the example of a POW (x,y) function object:
Template<typename T1, TypeName t2>
class Pow:public binary_function<t1,t2,t1>
{public
:
T1 operator () (T1 base, T2 exp) const
{return
std::p ow (BASE,EXP);
}
;
For example, we need a function object that computes any number cubic cube, which can be obtained by bind2nd (Pow<float,int> (), 3).
Finally, we end this article by customizing a function adapter. The functions to be implemented are: H (f (x), g (x)). First of all, this is a unary function object that accepts only one parameter x, which combines three function object h,f,g. This can be achieved by:
Template<typename h,typename f,typename g>
class Myadapter:unary_function<typename F::argument_type, TypeName h::return_type>
{public
:
myadapter (const h &h, const F &f, const G &g): M_h (H), M_f ( f), M_g (g) {}
typename H::return_type operator () (const typename F::argument_type &x) const
{return
m_h (M_f (x), M_g (x));
}
Private:
H m_h;
F M_f;
G m_g;
};
Finish