This article mainly introduces function objects, which may be called "high-order functions. It actually refers to a class of functions that can be passed into other functions or returned from other functions. In C ++, high-order functions are implemented as function objects. This article will introduce several boost C ++ libraries used to process function objects. Among them, boost. BIND can replace the famous STD: bind1st () and STD: bind2nd () functions from the C ++ standard, while boost. function provides a class for encapsulating function pointers. Finally, boost. Lambda introduces a method for creating anonymous functions.
1. Boost. Bind
Boost. bind simplifies a mechanism provided by STD: bind1st and STD: bind2nd template functions in C ++: using these functions with almost unlimited parameters, you can get the function of the specified signature. One of the best examples of this situation is multiple different algorithms defined in the C ++ standard.
#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); }
Algorithmstd::for_each
The third parameter must be a function or function object that only accepts the correct parameter. Ifstd::for_each
Executed. All elements in the specified container are passed in order.print
Function. However, it is complicated to use a function with different signatures. If you want to input the following functionsadd
To add a constant value to each element in the container and display the result.
void add(int i, int j) { std::cout << i + j << std::endl; }
Because STD: for_each () requires only one parameter function, you cannot directly input the add () function. You must modify the source code.
#include <iostream> #include <vector> #include <algorithm> #include <functional> class add : public std::binary_function<int, int, void> { public: void operator()(int i, int j) const { std::cout << i + j << 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(), std::bind1st(add(), 10)); }
The above program adds the value 10 to the containerVAnd use the standard output stream to display the results. The source code must be greatly modified to implement this function: The add () function has been converted into a function object derived from STD: binary_function.
Boost. Bind simplifies binding between different functions. It only contains one boost: BIND () template function, which is defined in boost/Bind. HPP. Use this function as follows:
#include <boost/bind.hpp> #include <iostream> #include <vector> #include <algorithm> void add(int i, int j) { std::cout << i + j << 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(), boost::bind(add, 10, _1)); }
Functions like add no longer need to be converted to function objects for STD: for_each. Use boost: bind. This function can be used to ignore the first parameter. Because the Add function requires two parameters, both of which must be passed to boost: bind. The first parameter is a constant value of 10, while the second parameter is a strange one._ 1.
_ 1 is called a placeholder (placeholder) and is defined in boost. Bind. In addition to _ 1, boost. Bind also defines _ 2 and _ 3. By using these placeholders, boost: BIND can be changed to a single, binary, or ternary function. For _ 1, boost: bind becomes a mona1 function. This is required because STD: for_each requires a mona1 function as its third parameter.
When this program is executed, STD: for_eachVThe first element in calls the mona1 function. The element value is passed into the mona1 function through placeholder _ 1. This placeholder and constant value are further passed to the Add function. Using this mechanism, STD: for_each can only see the mona1 function defined by boost: bind. Boost: bind itself only calls another function and passes a constant value or placeholder as a parameter to it.
The following example uses boost: bind to define a binary function for the STD: sort algorithm, which requires a binary function as its third parameter.
#include <boost/bind.hpp> #include <vector> #include <algorithm> bool compare(int i, int j) { return i > j; } int main() { std::vector<int> v; v.push_back(1); v.push_back(3); v.push_back(2); std::sort(v.begin(), v.end(), boost::bind(compare, _1, _2)); }
Because two placeholders _ 1 and _ 2 are used, boost: BIND () defines a binary function. STD: Sort () algorithm to containerVAnd sort the containers according to the returned values. Containers are sorted in descending order based on the compare () function definition.
However, since compare () itself is a binary function, using boost: BIND () is redundant.
#include <boost/bind.hpp> #include <vector> #include <algorithm> bool compare(int i, int j) { return i > j; } int main() { std::vector<int> v; v.push_back(1); v.push_back(3); v.push_back(2); std::sort(v.begin(), v.end(), compare); }
However, using boost: BIND () makes sense. For example, if the container is to be sorted in ascending order, you cannot modify the definition of the compare () function.
#include <boost/bind.hpp> #include <vector> #include <algorithm> bool compare(int i, int j) { return i > j; } int main() { std::vector<int> v; v.push_back(1); v.push_back(3); v.push_back(2); std::sort(v.begin(), v.end(), boost::bind(compare, _2, _1)); }
In this example, only the order of placeholders is changed:_ 2Is passed as the first parameter, while_ 1It is passed to compare () as the second parameter to change the sorting order.
2. Boost. Ref
Boost. Ref in this library is usually used with boost. Bind, so I will write them. It provides two functions: boost: ref () and boost: CREF (), which are defined in boost/Ref. HPP.
When the function to be used for Boost: BIND () carries at least one referenced parameter, boost. Ref is very important. Because boost: BIND () will copy its parameters, reference must be specially processed.
#include <boost/bind.hpp> #include <iostream> #include <vector> #include <algorithm> void add(int i, int j, std::ostream &os) { os << i + j << 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(), boost::bind(add, 10, _1, boost::ref(std::cout))); }
The preceding example uses the add () function in the previous section. However, this function requires a stream object reference to print the information. Because the parameters passed to boost: BIND () are passed in the value mode, STD: cout cannot be used directly. Otherwise, the function will try to create a copy of it.
By using the template function boost: ref (), a stream like STD: cout can be passed as a reference, and the above example can be compiled successfully.
To pass a constant object as a reference, you can use the template function boost: CREF ().
Iii. Boost. Function
To encapsulate function pointers, boost. function provides a class named boost: function. It is defined in boost/function. HPP and is used as follows:
#include <boost/function.hpp> #include <iostream> #include <cstdlib> #include <cstring> int main() { boost::function<int (const char*)> f = std::atoi; std::cout << f("1609") << std::endl; f = std::strlen; std::cout << f("1609") << std::endl; }
Boost: function can define a pointer to a function with a specific signature. The preceding example defines a pointer F, which can point to a function that accepts a parameter of the const char * type and returns a value of the int type. After the definition is complete, all functions matching the signature can be assigned to this pointer. This routine first assigns STD: atoi () to F, and then re-assigns it to STD: strlen ().
Note that the given data type does not require exact matching. Although STD: strlen () uses STD: size_t as the return type, it can also be assigned to F.
F is a function pointer, so the assigned function can be called through the overloaded operator () operator. Depending on which function is assigned, STD: atoi () or STD: strlen () will be called in the preceding example ().
If F is called without a function, a boost: bad_function_call exception is thrown.
#include <boost/function.hpp> #include <iostream> int main() { try { boost::function<int (const char*)> f; f(""); } catch (boost::bad_function_call &ex) { std::cout << ex.what() << std::endl; } }
Note: assigning 0 to a boost: function pointer will release the function currently assigned. Calling it after release will also cause the boost: bad_function_call exception to be thrown. To check whether a function pointer is assigned a value, you can use the empty () function or the operator bool () operator.
By using boost. function, class member functions can also be assigned to boost: Function objects.
#include <boost/function.hpp> #include <iostream> struct world { void hello(std::ostream &os) { os << "Hello, world!" << std::endl; } }; int main() { boost::function<void (world*, std::ostream&)> f = &world::hello; world w; f(&w, boost::ref(std::cout)); }
When calling such a function, the first parameter is passed in to indicate the specific object that the function is called. Therefore, the first parameter after the left parenthesis in the template definition must be a pointer to the specific class. The following parameter indicates the signature of the corresponding member function.
This program also uses boost: ref () from the boost. Ref library, which provides a convenient mechanism to pass references to boost. function.