Make the imitation function class adaptive

Source: Internet
Author: User
Suppose I have a Widget * pointer list and a function to determine whether such a pointer determines an interesting Widget: List <Widget *> widgetPtrs;
Bool isInteresting (const Widget * pw );

If I want to find the first pointer to an interesting Widget in the list, this is simple:

List <Widget *>: iterator I = find_if (widgetPtrs. begin (), widgetPtrs. end (),
IsInteresting );
If (I! = WidgetPtrs. end ()){
// Process the first one
} // Interesting point
// Widget pointer

However, if I want to find the first pointer to an interesting Widget, the obvious method fails to compile:

List <Widget *>: iterator I =
Find_if (widgetPtrs. begin (), widgetPtrs. end (), not1 (isInteresting); // error! Cannot compile

Instead, I have to pair the isInteresting application ptr_fun before the application not1:

List <Widget *>: iterator I =
Find_if (widgetPtrs. begin (), widgetPtrs. end (),
Not1 (ptr_func (isInteresting); // No problem
If (I! = WidgetPtrs. end ()){
// Process the first one
}

This will lead to some problems. Why do I have to apply ptr_fun to isInteresting before applying not1? What did ptr_fun do for me and how did I complete the above work?

The answer is somewhat surprising. The only thing ptr_fun does is make some typedef valid. That's it. Not1 needs these typedef, which is why
Not1 is applied to ptr_fun, but not1 cannot be applied directly to isInteresting. IsInteresting lacks not1 because it is a low-level function pointer.
Typedef.

Not1 is not the only component with requirements in STL. The four standard function adapters (not1, not2, bind1st, and bind2nd) all need some typedef, and some others need non-standard STL compatible adapters (such as those from SGI and Boost. The function objects that provide these necessary typedef are calledAdaptionBut the function objects that lack typedef are not adaptive. Adaptive function objects can be used in more scenarios than unsuitable function objects, so you should make your function objects adaptive as long as they can be done. This does not cost you anything, but it can make a convenient world for your function-like customers.

I know, I know. I'm playing tricks. I often mention "Some typedef" without telling you what it is. In the problem, typedef is argument_type,
First_argument_type, second_argument_type, and result_type, but not so straightforward, because different types of imitation Functions
Classes must provide different subsets of those names. In general, you don't need to know anything about typedef unless you are writing your own adapter (a topic not covered in this book. That's because
The formal methods that provide them are inherited from a base class, or, more precisely, a base structure. Operator () carries a real-name parameter-like function class. The inherited structure is std ::
Unary_function. Operator () contains two real-name function classes. The inherited structure is std: binary_function.

Well, in simple terms, unary_function and binary_function are templates, so you cannot inherit them directly. Instead, you must generate
Class inheritance, and you need to specify some type arguments. For unary_function, you must specify the parameter type and its
Return type. For binary_function, you must specify three types: the type of the first and second parameters of your operator, and the class returned by your operator.
Type.

There are two examples:

Template <typename T>
Class MeetsThreshold: public std: unary_function <Widget, bool> {
Private:
Const T threshold;

Public:
MeetsThreshold (const T & threshold );
Bool operator () (const Widget &) const;

};

Struct WidgetNameCompare:
Public std: binary_function <Widget, Widget, bool> {
Bool operator () (const Widget & lhs, const Widget & rhs) const;
};

In both cases, pay attention to the types passed to unary_function or binary_function, the operator () passed to the imitation function class, and the returned
Similarly, although the operator return type is passed to unary_function or binary_function as the last real parameter, it is a little odd.

You may notice that MeetsThreshold is a class, while WidgetNameCompare is a structure. MeetsThreshold has an internal status
(Its threshold data member), and the class is a reasonable way to encapsulate that information. WidgetNameCompare is stateless, so no private things are needed. Everything is
The authors of public imitation function classes often declare them as struct rather than class, maybe only because they can avoid inputting them before the base class and operator () function.
"Public ". Declaring such a function as a class or struct is purely a matter of personal style. If you are still refining your personal style, find some examples to see none
State STL imitation function classes (such as less <T> and plus <T>) are generally written as struct. Let's take a look.
WidgetNameCompare:

Struct WidgetNameCompare:
Public std: binary_function <Widget, Widget, bool> {
Bool operator () (cost Widget & lhs, const Widget & rhs) const;
}

Although operator's real parameter type is const
Widget &, but the Widget that is passed to binary_function. Generally, it is transmitted to unary_function or
The non-pointer type of binary_function removes the const and reference. (Don't ask why. The reason is not good or interesting. If you really want to know, write something that does not remove them
Program, and then dissect the compiler diagnostic results. If you have completed this stepStillIf you are interested in this issue, visit boost.org and check their work on features and function object adapters .)
This rule changes when the operator () parameter is a pointer. Here there is a structure similar to WidgetNameCompare, but this uses the Widget * pointer:

Struct PtrWidgetNameCompare:
Public std: binary_function <const Widget *, const Widget *, bool> {
Bool operator () (const Widget * lhs, const Widget * rhs) const;
};

Here, the type passed to binary_function and the type carried by operator ()Same. The general rule for the imitation functions with or returning pointers is that the type passed to unary_function or binary_function is operator () with or returned.

Do not forget all the redundant texts that use these unary_function and binary_function basics. These classes provide the typedef required by the function Object Adapter, so the adaptive function objects are generated from those classes. So let's do this:

List <Widget> widgets;

List <Widget>: reverse_iterator i1 = // find the last
Find_if (widgets. rbegin (), widgets. rend (), // applicable to widgets with a threshold of 10
Not1 (MeetsThreshold <int> (10); // (whatever it means)

Widget w (constructors );
List <Widget>: iterator i2 = // find the first
Find_if (widgets. begin (), widgets. end (), // WidgetNameCompare Definition
Bind2nd (WidgetNameCompare (), w); // the ranking order of widgets prior to w

If we do not inherit the imitation function class from unary_function or binary_function, none of these examples can be compiled, because both not1 and bind2nd work only with the adaptive function object.

STL function objects mimic C ++ functions, while a C ++ function has only one set of parameter types and one return type. As a result, STL secretly assumes that each function class has only one operator.
() Function, and the parameter and return type of this function must be passed to unary_function or binary_function (with the reference and pointer type rules we have just discussed
). This means that although it may be tempting, you cannot try to combine it by creating a single struct containing two operator () functions.
WidgetNameCompare and PtrWidgetNameCompare functions. If you do so, this function may be called in the same way
Pass the parameter to the binary_function) for adaptation, and a half-fit imitation function may only be better than completely unable to adapt.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.