Professional C__ - Marc Gregoire [223]
The second form of accumulate() allows the caller to specify an operation to perform instead of the default addition. This operation takes the form of a binary callback. Suppose that you want to calculate the geometric mean, which is the product of all the numbers in the sequence to the power of the inverse of the size. In that case, you would want to use accumulate() to calculate the product instead of the sum. You could write it like this:
#include #include #include using namespace std; int product(int num1, int num2) { return num1 * num2; } double geometricMean(const vector { double mult = accumulate(nums.begin(), nums.end(), 1, product); return pow(mult, 1.0 / nums.size()); } Code snippet from AlgorithmOverview\Accumulate.cpp Note that the product() function is passed as a callback to accumulate() and that the initial value for the accumulation is 1 (the identity for multiplication) instead of 0. To give you a second teaser about the power of C++11 lambda expressions, the geometricMean() function could be written as follows, without using the product() function: double geometricMeanLambda(const vector { double mult = accumulate(nums.begin(), nums.end(), 1, [](int num1, int num2){ return num1 * num2; }); return pow(mult, 1.0 / nums.size()); } Code snippet from AlgorithmOverview\Accumulate.cpp Later in this chapter you learn how to use accumulate() in the geometricMean() function without writing a function callback or lambda expression. C++11 Move Semantics with Algorithms Just like STL containers, STL algorithms are also optimized to use C++11 move semantics at appropriate times. This can greatly speed up certain algorithms, for example sort(). For this reason, it is highly recommended that you implement move semantics in your custom element classes that you want to store in containers. Move semantics can be added to any class by implementing a move constructor and a move assignment operator. Consult the “Move Semantics” section in Chapter 9 for details on how to add move semantics to your classes. LAMBDA EXPRESSIONS Syntax The syntax of a lambda expression is as follows: [capture_block](parameters) mutable exception_specification -> return_type {body} A lambda expression contains the following parts: Capture block: specifies how variables from the enclosing scope are captured and made available in the body of the lambda. Explained in the next section. Parameters: (optional) a list of parameters for the lambda expression. You can only omit this list if you do not need any parameters and you do not specify mutable, an exception specification and a return type. Omitting the return type is only allowed in certain cases as explained under the return_type bullet. For example: []{return 10;} The parameter list is similar to the parameter list for normal functions with the following differences: Parameters cannot have default values. Variable-length argument lists are not allowed. Unnamed parameters are not allowed. Mutable: (optional) if variables from the enclosing scope are captured by value, a copy of those variables will become available in the body of the lambda expression. Those copies are marked as const by default, meaning the lambda body cannot change the value of those copies. If the lambda expression is marked as mutable, those copies are not const and the body can modify those local copies. exception_specification: (optional) can be used to specify which exceptions the body of the lambda expression can throw. return_type: (optional) the type of the returned value. If the return_type part is omitted, the compiler will decide the return type as follows: If the body of the lambda expression is of the following form: { return expression; } the type of expression
C++11 adds a new feature called lambda expressions. This allows you to write anonymous functions inline, removing the need to write a separate function or to write a function object, and makes code easier to understand.