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

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

5 67 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 5
Dung lượng 20,97 KB

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

Nội dung

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

Trang 1

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

Trang 2

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);

Trang 3

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

Trang 4

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;

}

};

Trang 5

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

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