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

HandBooks Professional Java-C-Scrip-SQL part 91 pps

5 67 0

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

THÔNG TIN TÀI LIỆU

Nội dung

Usage To start using Boost.Function, include "boost/function.hpp", or any of the numbered versions, ranging from "boost/function/function0.hpp" to "boost/function/function10.hpp". If you know the arity of the functions you want to store in functions, it taxes the compiler less to include the exact headers that are needed. When including "boost/function.hpp", the other headers are all included, too. The best way to think of a stored function is a normal function object that is responsible for wrapping another function (or function object). It then makes perfect sense that this stored function can be invoked several times, and not necessarily at the time when the function is created. When declaring functions, the most important part of the declaration is the function signature. This is where you tell the function about the signature and return type of the functions and/or function objects it will store. As we've seen, there are two ways to perform such declarations. Here's a complete program that declares a boost::function that is capable of storing function-like entities that return bool (or a type that is implicitly convertible to bool) and accept two arguments, the first convertible to int, and the second convertible to double. #include <iostream> #include "boost/function.hpp" bool some_func(int i,double d) { return i>d; } int main() { boost::function<bool (int,double)> f; f=&some_func; f(10,1.1); } When the function f is first created, it doesn't store any function. It is empty, which can be tested in a Boolean context or with 0. If you try to invoke a function that doesn't store a function or function object, it throws an exception of the type bad_function_call. To avoid that problem, we assign a pointer to some_func to f using normal assignment syntax. That causes f to store the pointer to some_func. Finally, we invoke f (using the function call operator) with the arguments 10 (an int) and 1.1 (a double). When invoking a function, one must supply exactly the number of arguments the stored function or function object expects. The Basics of Callbacks Let's look at how we would have implemented a simple callback before we knew about Boost.Function, and then convert the code to make use of function, and examine which advantages that brings forth. We will start with a class that supports a simple form of callbackit can report changes to a value by calling whoever is interested in the new value. The callback will be a traditional C-style callbackthat is, a free function. This callback could be used, for example, for a GUI control that needs to inform observers that the user changed its value, without having any special knowledge about the clients listening for that information. #include <iostream> #include <vector> #include <algorithm> #include "boost/function.hpp" void print_new_value(int i) { std::cout << "The value has been updated and is now " << i << '\n'; } void interested_in_the_change(int i) { std::cout << "Ah, the value has changed.\n"; } class notifier { typedef void (*function_type)(int); std::vector<function_type> vec_; int value_; public: void add_observer(function_type t) { vec_.push_back(t); } void change_value(int i) { value_=i; for (std::size_t i=0;i<vec_.size();++i) { (*vec_[i])(value_); } } }; int main() { notifier n; n.add_observer(&print_new_value); n.add_observer(&interested_in_the_change); n.change_value(42); } Two functions, print_new_value and interested_in_the_change, have a signature that is compatible with what the notifier class supports. The function pointers are stored in a vector, and then invoked in a loop whenever the value changes. One syntax for invoking the functions is (*vec_[i])(value_); The dereferenced function pointer (which is what is returned from vec_[i]) is passed the value (value_). It's also valid to write the code differently, like this: vec_[i](value_); This may seem a bit nicer to the eye, but more importantly, it also allows you to replace the function pointer with Boost.Function without syntactic changes for invocation. Now, this works fine, but alas, function objects don't work at all with this notifier class. Actually, nothing but function pointers work, which is a serious limitation. It would work, however, if we were using Boost.Function. Rewriting the notifier class is fairly straightforward. class notifier { typedef boost::function<void(int)> function_type; std::vector<function_type> vec_; int value_; public: template <typename T> void add_observer(T t) { vec_.push_back(function_type(t)); } void change_value(int i) { value_=i; for (std::size_t i=0;i<vec_.size();++i) { vec_[i](value_); } } }; The first thing to do is to change the typedef to refer to boost::function rather than a function pointer. Before, we defined a function pointer; now we are using the generalization, which will soon prove its usefulness. Next, we change the signature of the member function add_observer to be parameterized on the argument type. We could have changed it to accept boost::function instead, but that means that users of our class would need to understand how function works [2] too, rather than just knowing about the requirements for the observer type. It should be duly noted that this change of add_observer is not a result of switching to function; the code would continue to work anyway. We make the change for generality; now, both function pointers, function objects, and instances of boost::function can be passed to add_observer, without any changes to existing user code. The code for adding elements to the vector is slightly altered, and now creates instances of boost::function<void(int)>. Finally, we change the code that invokes the functions to the syntax that can be used for functions, function objects, and instances of boost::function. [3] This extended support for different types of function-like "things" can immediately be put to use with a stateful function object, which represents something that could not be easily done using functions. [2] They should know about Boost.Function, but what if they don't? Everything that we add to an interface will need to be explained to users at some point in time. [3] Now we know that we should actually have been invoking like this from the beginning. class knows_the_previous_value { int last_value_; public: void operator()(int i) { static bool first_time=true; if (first_time) { last_value_=i; std::cout << "This is the first change of value, \ so I don't know the previous one.\n"; first_time=false; return; } std::cout << "Previous value was " << last_value_ << '\n'; last_value_=i; } }; This function object stores the previous value and prints it to std::cout whenever the value changes again. Note that the first time it is invoked, it doesn't know about the previous value. The function object detects this using a static bool variable in the function, which is initially set to true. Because static variables in functions are initialized when the function is first invoked, it is only set to true during the first invocation. Although static variables can be used like this to provide state for free functions too, we must understand that it does not scale well, and is hard to do safely in a multithreaded environment. So, function objects with state are always to be preferred over free functions with static variables. The notifier class doesn't mind this function object at allit complies with the requirements and is therefore accepted. This updated sample program demonstrates how this works. int main() { notifier n; n.add_observer(&print_new_value); n.add_observer(&interested_in_the_change); n.add_observer(knows_the_previous_value()); n.change_value(42); std::cout << '\n'; n.change_value(30); } The important line to examine is where we add an observer that isn't a function pointer, but an instance of the function object knows_the_previous_value. Running the program gives the following output: The value has been updated and is now 42 Ah, the value has changed. This is the first change of value, so I don't know the previous one. The value has been updated and is now 30 Ah, the value has changed. Previous value was 42 The great advantage here, more than relaxing the requirements on the functions (or rather, the additional support for function objects), is that we can introduce objects with state, which is a very common need. The changes that we made to the notifier . necessarily at the time when the function is created. When declaring functions, the most important part of the declaration is the function signature. This is where you tell the function about the

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

TÀI LIỆU CÙNG NGƯỜI DÙNG

  • Đang cập nhật ...

TÀI LIỆU LIÊN QUAN