4. Boost. Lambda
Anonymous functions, also known as Lambda functions, already exist in multiple programming languages, except C ++. However, with the help of the boost. Lambda library, they can be used in C ++ applications.
Lambda functions are designed to make the source code more compact and easier to understand. Take the code example in Section 1 of this chapter as an example.
#include <iostream> #include <vector> #include <algorithm> void print(int i) { std::cout << i << std::endl; } int main() { std::vector<int> v; v.push_back(1); v.push_back(3); v.push_back(2); std::for_each(v.begin(), v.end(), print); }
This program accepts the containerVAnd use the print () function to write them to the standard output stream. Since print () only writes a simple int, the implementation of this function is quite simple. Strictly speaking, it is so simple that it is more convenient to define it directly in the STD: for_each () algorithm, thus eliminating the need to add a function. Another advantage is that the Code is more compact, so that the algorithm and the function responsible for data output are not locally separated. Boost. Lambda makes it a reality.
#include <boost/lambda/lambda.hpp> #include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> v; v.push_back(1); v.push_back(3); v.push_back(2); std::for_each(v.begin(), v.end(), std::cout << boost::lambda::_1 << "\n"); }
Boost. Lambda provides several structures to define anonymous functions. The code is placed in the execution place, saving the overhead of encapsulating it as a function and then calling the corresponding function. As in the previous example, this program writes all the elements of container V to the standard output stream.
Similar to boost. Bind, boost. Lambda also defines three placeholders named _ 1, _ 2, and _ 3. Unlike boost. Bind, these Placeholders are defined in separate namespaces. Therefore, the first placeholder in this example is referenced through boost: Lambda: _ 1. To meet the requirements of the compiler, the corresponding header file boost/lambda/Lambda. HPP must be included.
Although the Code is located at the third parameter of STD: for_each () and looks weird, boost. Lambda can write Normal C ++ code. ContainerVElements can be written to the standard output stream through <to STD: cout.
Although boost. Lambda is very powerful, it also has some disadvantages. To insert a line feed in the preceding example, you must replace STD: Endl with "\ n" to compile the line feed successfully. Because the type required by the one-dimensional STD: Endl template function is different from that of the lambda function STD: cout <boost: Lambda: _ 1, it cannot be used here.
In the next version of C ++, Lambda functions may be added as part of the C ++ language itself to eliminate the need for separate libraries. However, it may take several years for the next version to be used by different compiler vendors. Previously, boost. Lambda proved to be a perfect alternative. The following example shows that this example only writes an element greater than 1 to the standard output stream.
#include <boost/lambda/lambda.hpp> #include <boost/lambda/if.hpp> #include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> v; v.push_back(1); v.push_back(3); v.push_back(2); std::for_each(v.begin(), v.end(), boost::lambda::if_then(boost::lambda::_1 > 1, std::cout << boost::lambda::_1 << "\n")); }
The header file boost/lambda/If. HPP defines several structures that allow the use of the IF statement within the lambda function. The most basic structure is the boost: Lambda: if_then () template function, which requires two parameters: the first parameter evaluates the condition. If it is true, the second parameter is executed. As shown in the example, each parameter can be a Lambda function.
In addition to boost: Lambda: if_then (), boost. lambda also provides the boost: Lambda: if_then_else () and boost: Lambda: if_then_else_return () template functions-they all require three parameters. In addition, it provides template functions for implementing loops, transformation operators, and even throw-allows Lambda functions to throw exceptions.
Although these template functions can be used to create complex Lambda functions in C ++, you must consider other aspects, such as readability and maintainability. Because others need to learn and understand additional functions, such as using boost: Lambda: if_then () to replace known C ++ keywords such as if and Else, the benefits of a Lambda function are usually reduced with its complexity. In most cases, a more reasonable method is to define a separate function using a familiar C ++ structure.
5. Exercise questions
1. Simplify the following program, convert the function object divided_by into a function, and replace the for loop with a standard C ++ Algorithm for output:
#include <algorithm> #include <functional> #include <vector> #include <iostream> class divide_by : public std::binary_function<int, int, int> { public: int operator()(int n, int div) const { return n / div; } }; int main() { std::vector<int> numbers; numbers.push_back(10); numbers.push_back(20); numbers.push_back(30); std::transform(numbers.begin(),numbers.end(),numbers.begin(),std::bind2nd(divide_by(), 2)); for (std::vector<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) std::cout << *it << std::endl; }
2. Simplify the following procedure and replace both for loops with the standard C ++ algorithm:
#include <string> #include <vector> #include <iostream> int main() { std::vector<std::string> strings; strings.push_back("Boost"); strings.push_back("C++"); strings.push_back("Libraries"); std::vector<int> sizes; for (std::vector<std::string>::iterator it = strings.begin(); it != strings.end(); ++it) sizes.push_back(it->size()); for (std::vector<int>::iterator it = sizes.begin(); it != sizes.end(); ++it) std::cout << *it << std::endl; }
3. Simplify the following program, modify the processors variable type, and replace the for loop with the standard C ++ algorithm:
#include <vector> #include <iostream> #include <cstdlib> #include <cstring> int main() { std::vector<int(*)(const char*)> processors; processors.push_back(std::atoi); processors.push_back(reinterpret_cast<int(*)(const char*)>(std::strlen)); const char data[] = "1.23"; for (std::vector<int(*)(const char*)>::iterator it = processors.begin(); it != processors.end(); ++it) std::cout << (*it)(data) << std::endl; }
6. Answers
The 1st questions are about the use of the boost: BIND () function. The function object divide_by in the question is a function object derived from binary_function, the function is to divide each element in the container by two for output. BIND is simplified here. If you do not consider the second problem, you can change the program
#include <boost/bind.hpp>#include <iostream> #include <vector> #include <algorithm> #include <functional> void divide_by(int i,int j){std::cout<<i/j<<std::endl;}void main() { std::vector<int> numbers; numbers.push_back(10); numbers.push_back(20); numbers.push_back(30); std::for_each(numbers.begin(), numbers.end(), boost::bind(divide_by,_1,10)); }
But it is also required to replace the For with the standard C ++ algorithm output, which is to examine the use of the boost: ref function, and then add the ref. The final answer is:
#include <boost/bind.hpp>#include <iostream> #include <vector> #include <algorithm> void divide_by(int i,int j,std::ostream &os){os<<i/j<<std::endl;}void main() { std::vector<int> numbers; numbers.push_back(10); numbers.push_back(20); numbers.push_back(30); std::for_each(numbers.begin(), numbers.end(), boost::bind(divide_by,_1,10,boost::ref(std::cout))); }
The 2nd question itself is a bit problematic. Some compilers may report duplicate it definitions and change the second one. In addition, the boost library I used is the latest. Somehow it is not compatible with vc6.0 and has included function. HPP prompts that STD: Abort is not supported, so the code written directly for this question is not tested. The for loop is replaced by for_each. The first for is to obtain the length and store it in sizes.
STD: for_each (strings. Begin (), strings. End (), sizes. push_back (boost: Lambda: _ 1 ))
STD: for_each (strings. Begin (), strings. End (), STD: cout <boost: Lambda: _ 1 <"\ n ")
The 3rd question is relatively simple, and its processors will certainly be changed to a function:
Boost: function <int (*) (const char *)> processors;
Processors = STD: atoi;
Const char data [] = "1.23 ";
For Loop processing is the same as 1.