1. Trang chủ
  2. » Công Nghệ Thông Tin

HandBooks Professional Java-C-Scrip-SQL part 94 doc

6 109 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 6
Dung lượng 21,56 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

stop.execute; // Some inspired songwriter has passed some lyrics std::string s="What a beautiful morning..."; record.set_function boost::bind&tape_recorder::record,&tr,s; record.exe

Trang 1

function f_ in a Boolean context If the function doesn't contain a target, a function or function object, this yields false, which means that we cannot invoke

it This is tested in the implementation of execute Here's a sample program that uses our new class:

int main() {

tape_recorder tr;

command play(boost::bind(&tape_recorder::play,&tr));

command stop(boost::bind(&tape_recorder::stop,&tr));

command forward(boost::bind(&tape_recorder::stop,&tr));

command rewind(boost::bind(&tape_recorder::rewind,&tr));

command record;

// Invoked from some GUI control

if (play.enabled()) {

play.execute();

}

// Invoked from some scripting client

stop.execute();

// Some inspired songwriter has passed some lyrics

std::string s="What a beautiful morning ";

record.set_function(

boost::bind(&tape_recorder::record,&tr,s));

record.execute();

}

To create the concrete commands, we use Boost.Bind to create function objects that, when invoked through the function call operator, calls the correct member function of tape_recorder These function objects are self-contained; they are nullary function objects, meaning that they can be directly invoked without passing any arguments, which is what a boost::function<void()> expects In other words, the following code snippet creates a function object that invokes the member function play on the instance of tape_recorder that it is configured with

boost::bind(&tape_recorder::play,&tr)

Trang 2

Normally, we wouldn't be able to store the returned function object from the call to bind, but because Boost.Function is compatible with any function object, this is possible

boost::function<void()> f(boost::bind(&tape_recorder::play,&tr));

Notice that the class also supports calling record, which takes an argument of type const std::string&, because of the member function

set_function Because the function object must be nullary, we need to bind the context so that record still gets its argument That, of course, is a job for binders Thus, before calling record, we create a function object that contains the string to be recorded

std::string s="What a beautiful morning ";

record.set_function(

boost::bind(&tape_recorder::record,&tr,s));

Executing the function object stored in record passes the string to

tape_recorder::record, invoked on the tape_recorder instance tr With Boost.Function and Boost.Bind, it is possible to achieve the decoupling that makes it possible for the invoking code to know nothing about the code being invoked It's immensely useful to combine these two libraries in this way Having shown you the command class, it's time for me to come clean All you really need, because of the power of Boost.Function, is the following:

typedef boost::function<void()> command;

Using Boost.Lambda with Boost.Function

Just as Boost.Function is compatible with the function objects that are created by Boost.Bind, it also supports Boost.Lambda, which also creates function objects Any function object that you create with the Lambda library is compatible with the corresponding boost::function We have covered some ground on binding

in the previous section, and the main difference is that it is possible to do even more with Boost.Lambda We can create these small, unnamed functions at ease, and store them in instances of boost::function for subsequent invocation

We have covered lambda expressions in the previous chapterany of the examples that were provided there produced function objects that could be stored in an

instance of function The combination of function and libraries that create function objects is extremely powerful

Trang 3

Thinking About the Cost

There's no such thing as a free lunch, as the saying goes, and this certainly applies

to Boost.Function, too There are some disadvantages of using Boost.Function compared to using function pointers, most notably the increase in size A function pointer obviously occupies the space of one function pointer (duh!), whereas an instance of boost::function is three times as large This can be an issue when there is a very large number of callbacks Function pointers are also slightly more efficient when invoked, because where a function pointer is invoked directly, Boost.Function may require two calls through function pointers Finally, there may

be cases where the backward compatibility with C libraries makes function

pointers the only choice

Although these are potential disadvantages of Boost.Function, it is not very often that these are real-world issues The extra size is still very small, and the overheard

of the (potential) extra call through a function pointer usually comes at a very small cost indeed compared to the time it takes to actually perform the

computations of the target function It should be the rare situation that mandates using function instead of Boost.Function The great advantages and the flexibility that is gained through using the library easily outweigh these costs

Under the Hood

As always, it is valuable to understand at least the basics of how a library works

We shall consider the three cases of storing and invoking a function pointer, a pointer to member function, and a function object These three are all different To see exactly how Boost.Function works, just look at the source codewe are going to

do things a bit differently, in an attempt to clearly show how different versions of such beasts demand slightly different approaches We will also have a class with different requirements, namely that when calling a member function, a pointer to

an instance of the class must be passed to the constructor of function1 (which

is the name of our class) function1 supports functions taking exactly one

argument A relaxation of the requirements compared to Boost.Function is that even for member functions, only the type of the result and the argument need to be supplied This is a direct consequence of the requirement that the constructor must

be passed a pointer to an instance of the class for which the member is to be called (the type is automatically deduced)

The approach we shall take is to create a parameterized base class that declares a virtual function for the function call operator; then, three classes are derived from

Trang 4

this base class for the different forms of function invocations that we are to

support These classes take care of all the work, while another, function1, decides which of these concrete classes to instantiate depending on the arguments

to the constructor Here is the base class for the invokers, invoker_base

template <typename R, typename Arg> class invoker_base {

public:

virtual R operator()(Arg arg)=0;

};

Next, we begin with the definition of function_ptr_invoker, which is a concrete invoker that derives publicly from invoker_base Its purpose is to invoke free functions The class also accepts two types, the return type and the argument type, and these are used for the constructor, which takes a function

pointer as argument

template <typename R, typename Arg> class function_ptr_invoker

: public invoker_base<R,Arg> {

R (*func_)(Arg);

public:

function_ptr_invoker(R (*func)(Arg)):func_(func) {}

R operator()(Arg arg) {

return (func_)(arg);

}

};

This class template can be used to call any free function that accepts one argument The function call operator simply invokes the function stored in func_ with the parameter it is given Note the (admittedly strange) line that declares a variable to store the function pointer

R (*func_)(Arg);

You can make that a little plainer using a typedef

typedef R (*FunctionT)(Arg);

FunctionT func_;

Next, we need a class template that can handle member function calls Remember that it should also require a pointer to an instance of the class type when

Trang 5

constructed, which is different from the way that Boost.Function works It does save us some typing, because the compiler, not the programmer, deduces the type

of the class

template <typename R, typename Arg, typename T>

class member_ptr_invoker :

public invoker_base<R,Arg> {

R (T::*func_)(Arg);

T* t_;

public:

member_ptr_invoker(R (T::*func)(Arg),T* t)

:func_(func),t_(t) {}

R operator()(Arg arg) {

return (t_->*func_)(arg);

}

};

This class template is very similar to the version for free function pointers It

differs from the previous one in that the constructor stores a member function pointer and a pointer to an object and the function call operator invokes the

member function (func_) on that object (t_)

Finally, we need a version that is compatible with function objects This is actually the easiest implementation of all, at least when defining it our way By using a single template parameter, we just state that the type T must indeed be a function object, because we intend to invoke it as such Enough said

template <typename R, typename Arg, typename T>

class function_object_invoker :

public invoker_base<R,Arg> {

T t_;

public:

function_object_invoker(T t):t_(t) {}

R operator()(Arg arg) {

return t_(arg);

}

};

Now that we have these building blocks in place, all that remains is to put the pieces together in our version of boost::function, the function1 class

Trang 6

We want a way to detect which kind of invoker to instantiate We can then save it

in a pointer to invoker_base The trick here is to provide constructors that are capable of detecting which type of invoker is correct for the supplied arguments It's just overloading, with a little twist involving parameterizing two of the

constructors

template <typename R, typename Arg> class function1 {

invoker_base<R,Arg>* invoker_;

Ngày đăng: 06/07/2014, 03:20

TỪ KHÓA LIÊN QUAN