Function object bit drop

xiaoxiao2021-03-06  99

Revision: 1.11 Date: 2006/01/11

Table of contents

What, why do you use it?

Preferably, it is designed to transmit

Boost.function

Boost.bind

Boost.mem_fn

Boost.Lambda

What, why do you use it?

Function object is a class object that has a modified form of a similar function due to the heavy load operator (). Usually use a function object to implement some form of callback, and the power object has the following advantages over the callback implemented by the traditional function pointer:

Save data between multiple calls. Since the function object can have a member variable, it is easy to save data between multiple calls. The conventional function must be very unnatural with a static partial variable or global variable.

Higher running efficiency. For calls that use the function pointer, the compiler cannot determine the name of the actual call, the generated machine instruction is only an indirect call; and the call to the function object, the compiler knows the name of the function (ie overload call call) The function of the operator is therefore possible to generate a directly called machine instruction, and the invocation operator can be invoked to obtain further efficiency, and a function of the function passed through the pointer is very difficult.

More flexible. Some operations can be provided in the function object, complete the initialization and extraction work of the relevant data.

Preferably, it is designed to transmit

The reason is that the algorithms that can be used in STL are designed to be delivered. Of course, you can use explicit template to pass reference, but you may bring problems (such as object cutting problems); carefully designed class or function templates may remove these problems, but you can guarantee that you are not used in these templates. STL? If the value is passed, the function object cannot be polymorphic and should be small. And in reality, the object is often not the case. At this time, we need to use C usual method PIMPL: move the data and / or polymorphism of large and / or polymorphic functions to another (implementation class), Then give your function object a pointer to this new class, this requires multiple function object instances to share an implementation class instance, Boost's Shared_Ptr is of course:

Template Class BPFCIMPL: PUBLIC UNARY_FUNCTION {Private: Widget W; INT X; ... Virtual ~ BPFCIMPL (); Virtual Void Operator () (Const T & Val) Const; Friend Class BPFC ;}; template {private: shared_ptr > piMPL; public: void operator () (const t & var) const {pIMPL-> operator () (val);} ...};

Boost.function

Sometimes we need to achieve a generalized callback, you can call back normal functions or function objects, as long as they meet the specified type (return value type, parameter number, and type), this can of course use template parameters to achieve this callback, Like find_if; but if you want to save such a callback function in a class, you usually need to turn this class into class template, and the class template must explicitly instantiate, so that the client's code is not simple enough, boost.function Through a smart packaging, the type of normal function and function object is unified, and it does not lose type security and has strong use value. Boost.Thread uses boost.function: class thread {public: explicit thread (const boost :: function0 );

Here, the constructor of thread declares that it accepts a number of parameters 0, the return value type is a VOID, whether it is a normal function or a function object. However, the convenience of Boost.Function also has a price. In addition to the increase in the space, the performance efficiency is also reduced, and those performance mad people have to pay attention.

Boost.bind

Sometimes we want to call back the function or function object does not satisfy the type of call to the callback, just because more than a few parameters that can be determined, it is very convenient to use boost.bind, it is std :: bind1st And std :: bind2nd, it can bind any parameter to a specific value, or pass the input parameters to any location. The binding method is also very flexible, and the function object and the binding of the member function are supported. For example, if you want to use Boost :: Thread to create a thread to perform a function: Void F (INT i), if you write Boost :: Thread Thrd (f) is wrong, because the Thread constructor declaration accepts a non-parameter and return type Void's type, and F is not possible to operate if the value of parameter i is provided. You can write:

Boost :: Thread THRD (Bind (f, 1)) // Assume that it is running F

Another example is true for each element in Vector V, and the function that is responsible for processing is a class A member function void A :: F (INT i), then write:

A a a; for_each (v.begin (), v.end (), bind (& a :: f, & a, _1));

Writing looks a bit strange, but as long as we know: Bind generates a function object, its writing must expresses the logic of the function object, which is the expression that calls the binding function, the logic is written. This expression is usually used to represent the first-form parameter, and _2 to represent the second formation in the parameters of the function object. . . For member functions, it can be considered that its first parameter is a THIS pointer. Take a few examples, assume that there is a function Void F (INT I, INT J, INT M)

Bind (f, _1, _1); // Generate a function object with a parameter, use this parameter as the first and second unparallelene call f Bind (f, _1, _1 1, _2); / / Generate a function object with two parameters, with the first parameter as F, the first parameter plus 1 as a second inner parameter, the second parameter as the third real Participate to call f

Boost.mem_fn

There is a container V of a Shape object, wants to call the Draw method for each object that it is accommodated.

For_each (v.begin (), v.end (), & shape :: draw is wrong, because you can't call on the member function and the member function pointer, you must call the member function through an object or object pointer. The function object generated by Boost.mem_fn is to point to the pointer or reference or smart pointer to the member function. It can support multiple parameters, so it is generally generalized in STL.

Boost.Lambda

Have a container for an object pointer, what do you do when you want to destroy the objects you reference? Hand writing loop? Slightly trouble; use for_each seems to save the troubles of writing cycles, but have to write a function object in another place, it seems to be more trouble, it seems to spread a local solution to the outside, and will reduce the code. Readability. This time Boost.Lambda may be helpful:

For_each (v.begin (), v.end (), bind (delete_ptr (), _1))

Here, the bind (delete_ptr (), _1) is a lambda expression, which generates an unknown function object class for this expression (a bit like anonymous class like Java), effectively avoiding the troubles of handwriting simple function objects. . For the general overloaded operators, usage and in C , such as <<, =, etc .; for special overloaded operators such as New, Delete, etc., there is a corresponding expression (in example, DELETE_PTR ()); the function calls the BIND provided by Lambda; even the control structure is supported.

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

New Post(0)