Effective STL Terms 40

zhaozj2021-02-11  209

Terms 40: Make the imitation functionality

Suppose I have a Widget * pointer's list and a function to determine if such a pointer determines an interesting widget:

List widgetptrs;

Bool isinteresting (Const Widget * Pw);

If I want to find the first pointer to interesting Widget in list: This is simple:

List :: itrator i = find_if (widgetptrs.begin (), widgetptrs.end (),

isinteresting;

IF (i! = widgetPTRS.End ()) {

... // Treat the first one

} // Interesting pointing

// Widget's pointer

But if I want to find the first pointer to the unresporated Widget, it is obvious that the method is compiled:

List :: item i =

Find_if (WidgetPTRS.BEGIN (), widgetptrs.end (),

Not1 (isinteresting)); // Error! Cannot compile

Instead, I have to apply PTR_FUN to ISINTERESTISTING before applying NOT1:

List :: item i =

Find_if (WidgetPTRS.BEGIN (), widgetptrs.end (),

Not1 (PTR_FUNC (ISINTERESTING)))))))))))); // No problem

IF (i! = widgetPTRS.End ()) {

... // Treat the first one

} // Pointer to widget

That will lead some questions. Why do I have to apply PTR_FUN to ISINTERESTING? PTR_FUN did what I did, how to finish the work above?

Some of the answers are amazing. The only thing PTR_FUN does make some typedef valid. That's it. NOT1 needs these typefef, which is why not1 can be applied to PTR_FUN, but not directly apply Not1. Because it is a low-level function pointer, IsInteresting lacks typedef required for Not1.

NOT1 is not the only component that requires those required by STL. All four standard function adapters (NOT1, NOT2, BIND1ST, and BIND2ND) require some typedef, some other person-written non-standard STL compatible adapters (such as from SGI and Boost-see Terms 50). The function object that provides these necessary typedef is called adaptable, and lack of the function objects of TypeDef are uncomfortable. Adapted to uncomfortable function objects can be used for more scenes, so as long as you can do you, you should make your function object adapt. This doesn't cost anything, and it can buy a convenient world for customers who are imitated.

I know I know. I am selling, often mentioning "some typefef" without telling you what. The typefef in the problem is argument_type, first_argument_type, second_argument_type and result_type, but not so straightforward, because different types of imitation functionals need to provide those names of different subsets. Overall, unless you are writing your own adapter (this book does not have the subject of the subject), you don't need to know anything about TypeDef. That is because the regular way to provide them is from a base class, or, more accurately, one base structure, inherit them. Operator () with a parameter of the imitation function class, the structure to be inherited is std :: unary_function. Operator () has two parameters of imitation function class, the structure to inherit is std :: binary_function. Ok, simply, unary_function and binary_function are templates, so you can't inherit them directly. Instead, you must inherit from the class they generated, and then you need some type of type parameters. For unary_function, you must specify the type of parameters that is taken by your oscillatic function class and its return type. For binary_function, you have to specify three types: your Operator's first and second parameters, and return your Operator.

Here are two examples:

Template

Class MeetSthreshold: Public Std :: unary_function {

Private:

CONST T threshold;

PUBLIC:

Meetsthreshold (Const T & thReshold);

Bool Operator () (Const Widget &) Const;

...

}

Struct WidgetNameCompare:

Std :: binary_function {

Bool Operator () (Const Widget & lh, Const Widget & rhs) Const;

}

In both cases, pay attention to the type of unary_function or binary_function and the Operator () passing to the imitation function class, the same, although the return type of the Operator is passed to Unary_Function or binary_function, there is a little quirky.

You may notice that MeetSthreshold is a class, and WidgetNameCompare is a structure. MeetSthresh has internal status (its threshold data member), and class is a reasonable method of encapsulating those information. WidgetNameCompare is not status, so there is no need for any private. Everything is the authors of public imitation functionals often declare them as struct rather than Class, perhaps only because you can avoid entering "public" in front of the base class and Operator () functions. Declaring such an imitation function as a Class or Struct is purely a personal style. If you are still refining your personal style, you want to find some imited objects, see where there is no state STL yourself, such as Less , Plus , etc.) is generally written as Struct. Take a look at WidgetNameCompare:

Struct WidgetNameCompare:

Std :: binary_function {bool operator () (Cost Widget & lh, Const Widget & rhs) const;

}

Although the parameter type of Operator is Const Widget &, it is transmitted to binary_function. In general, the non-pointer type transmitted to Unary_Function or Binary_Function has removed Const and reference. (Don't ask why. Reasons are not very good. If you really want to know, write some programs that don't get rid of them, then to dissect the compiler diagnosis results. If you have completed this, you still have interest to this issue Access Boost.org (see Terms 50) and then look at their work about characteristics and function object adapters.)

This rule changed when the parameter of the operator () is a pointer. There is a structure similar to WidgetNameCompare, but this uses widget * pointer:

Struct PtrwidgetNameCompare:

Std: binary_function {

Bool Operator () (Const Widget * LHS, Const Widget "RHS) Const;

}

Here, pass the type of binary_function and the type of Operator (). A general rule for the imitation function for bringing or returning a pointer is to pass the type of unary_function or binary_function is the type of Operator () with or returned.

Don't forget all redundant texts that use these unary_function and binary_function base classes. These classes provide the typedef required for the function object adapter, so inheritably generates the adaptive function object from those class. That makes us do this:

List widgets;

...

List :: Reverse_iterator i1 = // Find the last one

Find_if (widgets.rbegin (), widgets.rend (), // suitable for threshold 10 Widget

NOT1 (MeetSthreshold (10)))); // (no matter what means)

Widget W (constructor parameters);

List :: item I2 = // Find the first one

Find_if (widgets.begin (), widgets.end (), // widgetnamecompare definition

Bind2nd (WidgetNameCompare (), W); //'s sort order Popular Widget

If we don't inherit the imitation function class from Unary_Function or Binary_Function, these examples cannot be compiled, because NOT1 and BIND2nd are only working with adaptive function objects.

The STL function object imitates the C function, and a C function has only one set of parameter types and a return type. As a result, STL secretly assumes that each imitation function class has only one Operator () function, and the parameters of this function should be passed to Unary_Function or Binary_Function (consistent with the references we just discussed and the rules of the pointer type). This means that although it may be very attractive, you can't create the functionality of the WidgetNameCompare and PtrwidgetNameCompare, which is unique to try to set up a separate structure of two Operator () functions. If you have done it, this imitation function may be able to adapt with up to one of its call form (you pass parameters to binary_function), and a method of improving only half adaptation can be better than it is better than it is. Sometimes it is necessary to give an example of multiple call forms (so gives up the adaptive), clauses 7, 20, 23, and 25. But that type of imitation function is exception, not rules. Adaptedness is important, every time you write the fixing function class, you should work hard to promote it.

转载请注明原文地址:https://www.9cbs.com/read-4766.html

New Post(0)