O''''Reilly Network For Information About''''s Book part 84 docx

6 204 0
O''''Reilly Network For Information About''''s Book part 84 docx

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

Thông tin tài liệu

constants can make the expression significantly easier to understand; the same goes for variables. To create named constants and variables, one simply has to define a variable of the type boost::lambda::constant_type<T>::type and boost::lambda::var_type<T>::type, where T is the type of the wrapped constant or variable. Consider this use of a lambda expression: for_all(vec, std::cout << constant(' ') << _ << constant('\n')); It can be rather tedious to use constant all of the time. Following is a sample program that names two constants, newline and space, and uses them in a lambda expression. #include <iostream> #include <vector> #include <algorithm> #include "boost/lambda/lambda.hpp" int main() { using boost::lambda::constant; using boost::lambda::constant_type; constant_type<char>::type newline(constant('\n')); constant_type<char>::type space(constant(' ')); boost::lambda::placeholder1_type _; std::vector<int> vec; vec.push_back(0); vec.push_back(1); vec.push_back(2); vec.push_back(3); vec.push_back(4); for_all(vec,std::cout << space << _ << newline); for_all(vec, std::cout << constant(' ') << _ << constant('\n')); } This is a convenient way of avoiding repetitious typing, and making the lambda expressions a little bit clearer. Following is a similar example, which first defines a type memorizer, which keeps track of all the values that have been assigned to it. Then, a named variable is created using var_type, to be used in a subsequent lambda expression. You'll soon see that named constants tend to be needed much more often than named variables, but there are situations where it makes perfect sense to use named variables, too. [4] [4] Especially when using the lambda looping constructs. #include <iostream> #include <vector> #include <algorithm> #include "boost/lambda/lambda.hpp" template <typename T> class memorizer { std::vector<T> vec_; public: memorizer& operator=(const T& t) { vec_.push_back(t); return *this; } void clear() { vec_.clear(); } void report() const { using boost::lambda::_1; std::for_each( vec_.begin(), vec_.end(), std::cout << _1 << ","); } }; int main() { using boost::lambda::var_type; using boost::lambda::var; using boost::lambda::_1; std::vector<int> vec; vec.push_back(0); vec.push_back(1); vec.push_back(2); vec.push_back(3); vec.push_back(4); memorizer<int> m; var_type<memorizer<int> >::type mem(var(m)); std::for_each(vec.begin(),vec.end(),mem=_1); m.report(); m.clear(); std::for_each(vec.begin(),vec.end(),var(m)=_1); m.report(); } That's all there is to it, but before you think that you've got all this nailed down, answer this: What should be the type T in the following declaration? constant_type<T>::type hello(constant("Hello")); Is it a char*? A const char*? No, it's actually a constant reference to an array of six characters (the terminating null counts, too), which gives us this: constant_type<const char (&)[6]>::type hello(constant("Hello")); This isn't a pretty sight, and it's a pain for anyone who needs to update the literalwhich is why I find it much cleaner to use the good old std::string to get the job done. constant_type<std::string>::type hello_string(constant(std::string("Hello"))); This way, you have to type a little bit more the first time, but you don't need to count the characters, and if there's ever a need to change the string, it just works. Where Did ptr_fun and mem_fun Go? Perhaps you've already thought of thisbecause Boost.Lambda creates standard- conforming function objects, there's actually no need to remember the adaptor types from the Standard Library. A lambda expression that binds the function or member function works just as well, and the syntax is the same regardless of the type that's being bound to. This allows the code to stay focused on the task, rather than on some syntactic peculiarity. Here's an example that illustrates these benefits: #include <iostream> #include <vector> #include <algorithm> #include <functional> #include "boost/lambda/lambda.hpp" #include "boost/lambda/bind.hpp" void plain_function(int i) { std::cout << "void plain_function(" << i << ")\n"; } class some_class { public: void member_function(int i) const { std::cout << "void some_class::member_function(" << i << ") const\n"; } }; int main() { std::vector<int> vec(3); vec[0]=12; vec[1]=10; vec[2]=7; some_class sc; some_class* psc=&sc; // Bind to a free function using ptr_fun std::for_each( vec.begin(), vec.end(), std::ptr_fun(plain_function)); // Bind to a member function using mem_fun_ref std::for_each(vec.begin(),vec.end(), std::bind1st( std::mem_fun_ref(&some_class::member_function),sc)); // Bind to a member function using mem_fun std::for_each(vec.begin(),vec.end(), std::bind1st( std::mem_fun(&some_class::member_function),psc)); using namespace boost::lambda; std::for_each( vec.begin(), vec.end(), bind(&plain_function,_1)); std::for_each(vec.begin(),vec.end(), bind(&some_class::member_function,sc,_1)); std::for_each(vec.begin(),vec.end(), bind(&some_class::member_function,psc,_1)); } There's really no need to make the case for lambda expressions and binders here, is there? Rather than using three different constructs for performing virtually the same thing, we'll let bind figure out what to do, and then be done with it. In the example, it was necessary to use std::bind1st to enable the instance of some_class to be bound to the invocation; with Boost.Lambda, that's part of the job description. So, the next time you are wondering whether to use ptr_fun, mem_fun, or mem_fun_refstop wondering and use Boost.Lambda instead! Arithmetic Operations Without <functional> We often perform arithmetic operations on elements from sequences, and the Standard Library helps out by providing a number of binary function objects for arithmetic operations, such as plus, minus, divides, modulus, and so on. However, these function objects require more typing than one likes, and often one argument needs to be bound, which in turn requires the use of binders. When nesting such arithmetic, expressions quickly become unwieldy, and this is yet another area where lambda expressions really shine. Because we are dealing with operators here, both in arithmetic and C++ terms, we have the power to directly code our algorithms as lambda expressions. To give a short motivation, consider the trivial problem of incrementing a numeric value by 4. Then, consider doing that same inside a Standard Library algorithm (such as TRansform). Although the first comes very naturally, the second is a totally different beast (which will drive you into the arms of handwritten loops). Using a lambda expression, focus remains on the arithmetic. In the following example, we'll first use std::bind1st and std::plus to add 4 to each element of a containerand then we'll use lambda to subtract 4. #include <iostream> #include <vector> #include <algorithm> #include <functional> #include "boost/lambda/lambda.hpp" #include "boost/lambda/bind.hpp" int main() { using namespace boost::lambda; std::vector<int> vec(3); vec[0]=12; vec[1]=10; vec[2]=7; . mem(var(m)); std: :for_ each(vec.begin(),vec.end(),mem=_1); m.report(); m.clear(); std: :for_ each(vec.begin(),vec.end(),var(m)=_1); m.report(); } That's all there is to it, but before you. There's really no need to make the case for lambda expressions and binders here, is there? Rather than using three different constructs for performing virtually the same thing, we'll. free function using ptr_fun std: :for_ each( vec.begin(), vec.end(), std::ptr_fun(plain_function)); // Bind to a member function using mem_fun_ref std: :for_ each(vec.begin(),vec.end(),

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

Tài liệu cùng người dùng

Tài liệu liên quan