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

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

6 62 0

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

THÔNG TIN TÀI LIỆU

Nội dung

if_then_else_return, which calls the conditional operator. Let's take a closer look at the whole range of control structures, starting with if and switch. Remember that to use if-constructs, "boost/lambda/if.hpp" must be included. For switch, "boost/lambda/switch.hpp" must be included. The following examples all assume that the declarations in the namespace boost::lambda have been brought to the current scope through using declarations or a using directive. (if_then(_1<5, std::cout << constant("Less than 5")))(make_const(3)); The if_then function starts with a condition, followed by a then-part; in the preceding code, if the argument passed to the lambda function is less than 5 (_1<5), "Less than 5" is printed to std::cout. You'll note that when we invoke this lambda expression with the numeric value 3, we cannot pass it directly, like so. (if_then(_1<5,std::cout << constant("Less than 5")))(3); This would result in a compiler error, because 3 is an int, and an rvalue of type int (or any built-in type for that matter) cannot be const qualified. Thus, one has to use the utility make_const here, which does nothing more than return a reference to const of its argument. Another option is to wrap the whole lambda expression in a call to const_parameters, like so: (const_parameters( if_then(_1<5,std::cout << constant("Less than 5"))))(3); const_parameters is useful to avoid having to wrap each of several arguments with make_const. Note that when using this function, all of the parameters to the lambda expression are considered (references to) const. Now look at how if_then looks using the alternative syntax. (if_(_1<5) [std::cout << constant("Less than 5")])(make_const(3)); This notation has a greater resemblance to the C++ keyword, but it does exactly the same thing as if_then. The function if_ (note the trailing underscore) is followed by the parenthesized condition, which in turn is followed by the then- statement. Again, choosing between these syntax alternatives is simply a matter of taste. Now, let's take a look at the if-then-else constructs; they're very similar to if_then. (if_then_else( _1==0, std::cout << constant("Nothing"), std::cout << _1))(make_const(0)); (if_(_1==0) [std::cout << constant("Nothing")]. else_[std::cout << _1])(make_const(0)); When adding the else-part using the alternative syntax, note that a period precedes the else_. The return type of these lambda expressions is void, but there is also a version that returns a value, by using the conditional operator. There are some non-trivial rules for the types of such expressions (I won't go through them here, but see the online documentation for Boost.Lambda or the C++ Standard [§5.16] for the nitty- gritty details). Here's an example, where the return value is assigned to a variable, similar to how you would use the conditional operator for ordinary expressions. int i; int value=12; var(i)=(if_then_else_return (_1>=10,constant(10),_1))(value); There is no version of the alternative syntax for this construct. That's it for if-then- else, which brings us to the switch-statement, which differs somewhat from the standard C++ switch. (switch_statement _1, case_statement<0> (var(std::cout) << "Nothing"), case_statement<1> (std::cout << constant("A little")), default_statement (std::cout << _1)) )(make_const(100)); The call to switch_statement starts with the condition variable, which in our case is _1, the first argument to the lambda expression. This is followed by (up to nine) case constants, which have labels of integer type; these must be constant integral expressions. We provide two such constants, for 0 and 1 (note that they could have any value acceptable for integral types). Finally, we add the optional default_statement, which is executed if the evaluation of _1 doesn't match any of the other constants. Note that a break-statement is implicitly added to each case constant, so there's no need to explicitly exit from a switch (which is a Good Thing for those maintaining the code [6] ). [6] Spokesmen of fall-through case-statements; please excuse this blasphemy. Now let's examine the iteration statements, for, while, and do. To use any of these, you must include the header "boost/lambda/loops.hpp" first. Boost.Lambda's equivalent of C++'s while is while_loop. int val1=1; int val2=4; (while_loop(_1<_2, (++_1,std::cout << constant("Inc \n"))))(val1,val2); A while_loop statement is executed until the condition becomes false; here the condition is _1<_2, which is followed by the body of the loop, the expression ++_1,std::cout << constant("Inc \n"). Of course, the condition and the loop body must, themselves, be valid lambda expressions. The alternative syntax is closer to the C++ syntax, just as was the case with if_. int val1=1; int val2=4; (while_(_1<_2) [++_1,std::cout << constant("Inc \n")])(val1,val2); The form is while_(condition)[substatement], and it does save a couple of keystrokes…but personally I find the function call syntax easier to read for while, although I (irrationally) find if_ easier to parse than if_then( ). Go figure. do_while_loop is naturally very similar to while_loop, but the substatement is always executed at least once (unlike while, the condition is evaluated after each execution). (do_while_loop(_1!=12,std::cout << constant("I'll run once")))(make_const(12)); The corresponding alternative syntax is (do_[std::cout << constant("I'll run once")].while_(_1!=12))(make_const(12)); Finally, there's the for loop equivalent, for_loop. In the following example, a named, delayed variable is used to make the lambda expression more readable. We've come across delayed variables before through the use of constant and var. Delayed variables with names is a way of avoiding having to type constant or var for constants and variables, respectively. Instead, they're given a name of your choice with which they can later be referred. The general form for the loop is for_loop(init-statement, condition, expression, statement)that is, it's like a regular for statement but the statement is part of the function (arguments). int val1=0; var_type<int>::type counter(var(val1)); (for_loop(counter=0,counter<_1,++counter,var(std::cout) << "counter is " << counter << "\n"))(make_const(4)); With the alternative syntax, statement is separated from initialization, condition, and expression. (for_(counter=0,counter<_1,++counter)[var(std::cout) << "counter is " << counter << "\n"])(make_const(4)); The example initializes the delayed variable counter to 0, the condition is counter<_1, and the expression is ++counter. This concludes the section on control structures. For most problems that I've encountered and solved with lambda expressions, I can actually do without them, but sometimes, they are real lifesavers. Regarding the choice of syntactic version, the best way to figure out which to use is probably to experiment using both, and get a feel for which version suits your needs the best. It should be noted that when using switch and the loop constructs, the lambda expressions quickly become large enough to make them hard to follow if you're not fairly accustomed to using the library. Some care should thus be taken, and if an expression seems too hard to parse for your fellow programmers, consider a separate function object instead. (Or have them practice using Boost.Lambda more!) Casting in Lambda Expressions There are four special "cast operators" [7] that allow casting of types in lambda expressions: ll_dynamic_cast, ll_static_cast, ll_reinterpret_cast, and ll_const_cast. The names are different from the corresponding C++ keywords because these cannot be overloaded. To use these casts, include the header "boost/lambda/casts.hpp". These functions work like their C++ cast operator equivalents; they take an explicit template argument, which is the type to cast to, and an implicit template argument, which is the source type. In our first example, we will use two classes, imaginatively named base and derived. We'll create two pointers to base, one of them will point to an instance of base, and the other to an instance of derived. Using ll_dynamic_cast, we will try to extract a derived* from both of these pointers. [7] Technically, they are template functions returning function objects. #include <iostream> #include "boost/lambda/lambda.hpp" #include "boost/lambda/casts.hpp" #include "boost/lambda/if.hpp" #include "boost/lambda/bind.hpp" class base { public: virtual ~base() {} void do_stuff() const { std::cout << "void base::do_stuff() const\n"; } }; class derived : public base { public: void do_more_stuff() const { std::cout << "void derived::do_more_stuff() const\n"; } }; int main() { using namespace boost::lambda; base* p1=new base; base* p2=new derived; derived* pd=0; (if_(var(pd)=ll_dynamic_cast<derived*>(_1)) . than 5")))(make_const(3)); The if_then function starts with a condition, followed by a then -part; in the preceding code, if the argument passed to the lambda function is less than 5 (_1<5),. constant("Nothing")]. else_[std::cout << _1])(make_const(0)); When adding the else -part using the alternative syntax, note that a period precedes the else_. The return type of these. condition, expression, statement)that is, it's like a regular for statement but the statement is part of the function (arguments). int val1=0; var_type<int>::type counter(var(val1)); (for_loop(counter=0,counter<_1,++counter,var(std::cout)

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