Examples of lambda functions, std::for_each / max_element / remove_if etc
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
4
down vote
favorite
I have written a cpp program which demonstrates the use of the following functionalities in modern cpp.
Lambda Functions
std::generate
std::vector
std::erase
std::remove_if
std::remove
std::max_element
std::for_each
std::shuffle
I want to understand the following
(1) Have I written the code properly or there are somethings which needs to be improved.
(2) Will it be helpful if I write it as a blog for others. If yes, do I need to add more comments etc to make it more consumable?
/*
* Copyright Rishi Agrawal <rishi.b.agrawal@gmail.com>
*
* The idea behind this program is to understand how to use the following.
* Lambda Functions
* std::generate
* std::vector
* std::erase
* std::remove_if
* std::remove
* std::max_element
* std::for_each
* std::shuffle
*/
#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
#include <cassert>
void printInt(int n)
std::cout << " " << n;
/**
* @brief Function to demonstrate lambda functions.
*
* @param v - the vector to use.
*/
void playingWithLambdaFunctions(std::vector<int> &v)
/* Generate the elements in the vector. The lambda function take a variable
* and increments it everytime. Using mutable so that the value of the
* variable is preserved accross invocations of lambda.*/
std::generate(v.begin(), v.end(), [n = 0]() mutable n = n + 5; return n;);
/* Print the vector using a lambda function. Here the value at a particular
* position is passed as n. This passing is by value. */
std::for_each(v.begin(), v.end(), (int n) std::cout << " " << n; );
/* Other way of printing where we use a unary function for printing. */
std::cerr << "nnPrinting using for_each and unary_functionnn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnPrinting and increasing values of the passed integers. "
"This will not change the sequence as the values are "
"passed by value.nn";
std::for_each(v.begin(), v.end(), (int n)
std::cout << " CurrentVal(" << n << ")";
n = n + 1; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
std::cerr << "nnPrinting to check if the values changed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnPrinting and increasing values of the passed integers. "
"This will CHANGE the values as we are passing the "
"numbers by reference.nn";
std::for_each(v.begin(), v.end(), (int &n)
std::cout << " CurrentVal(" << n << ")";
n = n + 1; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
std::cerr << "nnPrinting to check if the values changed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnIncreasing values of the passed integers in the vector. "
"This will CHANGE the values as we are passing the "
"numbers by reference. This time we are also passing the "
"value with which we want to increase.nn";
int increment = 5;
std::for_each(v.begin(), v.end(), [increment](int &n)
std::cout << " CurrentVal(" << n << ")";
n = n + increment; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
std::cerr << "nnPrinting to check if the values changed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnConverting all the odd numbers to even by increasing by 1."
" This will CHANGE the values as we are passing the "
"numbers by reference.nn";
std::for_each(v.begin(), v.end(), (int &n) if (n%2) n++; );
std::cerr << "nnPrinting to check if the values changedX.nn";
std::for_each(v.begin(), v.end(), printInt);
/**
* @brief Do some more operations like remove_if, and remove on vector.
*
* @param v - the vector to use.
*/
void otherSequenceOperations(std::vector<int> &v)
/* Remove the elements which are divisible by 4 */
std::sort(v.begin(), v.end());
std::cerr << "nnPrinting to check if the numbers are sorted.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "nnRemoving all the numbers which are divisible by 4";
auto eraseBegin = std::remove_if(v.begin(), v.end(), (const int n)
if (n%4 == 0)
return true;
else
return false;
);
/* std::remove_if moves the removable elements to the end of the list and
* returns the iterator to the begining of the elements to be removed. */
v.erase(eraseBegin, v.end());
std::cerr << "nnPrinting to check if the numbers are removed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "nAdding some more elements";
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
std::cout << "nPrinting the freshly added numbers";
std::for_each(v.begin(), v.end(), printInt);
/* Remove the elements which is equal to 22. */
int numberToRemove = 22;
eraseBegin = std::remove(v.begin(), v.end(), numberToRemove);
v.erase(eraseBegin, v.end());
std::cerr << "nnPrinting to check if 22 was removed. We are counting the "
"presence of the number 22 in the vector. If it is not 0, we "
" exit.nn";
assert(0 == count(v.begin(), v.end(), numberToRemove));
std::for_each(v.begin(), v.end(), printInt);
/**
* @brief Function to demonstrate the std::max_element.
*
* @param v - the vector to be used.
*/
void playWithMaxElement(std::vector <int> &v)
auto maxElementIt = std::max_element(v.begin(), v.end());
auto maxElement = *(maxElementIt);
/* Replace the max element with -1.*/
std::replace(v.begin(), v.end(), maxElement, -1);
std::cout << "nnPrinting after replacing " << maxElement << " with "
<< -1 << "n";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "n";
/* Replace the max element in one line. */
std::replace(v.begin(),
v.end(),
*(std::max_element(v.begin(), v.end())), // Return the position
// of the max element.
100);
std::cout << "nnPrinting after replacing max element with 100 n";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "n";
/* Writing our max function */
int ourMax = 0;
v.push_back(std::numeric_limits<int>::max());
std::for_each(v.begin(), v.end(), [&ourMax](int n)
if (n > ourMax)
ourMax = n;
);
std::cerr << "nOur max is " << ourMax;
assert(ourMax == std::numeric_limits<int>::max());
/**
* @brief Shuffles the vector
*
* @param v - the vector to be shuffled.
*/
void shuffleVector(std::vector <int> &v)
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
std::cerr << "nnPrinting the shuffled vector.nn";
std::for_each(v.begin(), v.end(), printInt);
int main()
int sizeOfVector = 10;
/* Create the vector. */
std::vector <int> v = std::vector <int>(sizeOfVector);
std::cout << "nPrint the created vector";
std::for_each(v.begin(), v.end(), printInt);
std::cout <<"nDoing some operations in the vector";
playingWithLambdaFunctions(v);
otherSequenceOperations(v);
shuffleVector(v);
playWithMaxElement(v);
return 0;
Makefile is
CPP_STANDARD="c++17"
STANDARD_FLAG="-std=$(CPP_STANDARD)"
OUTPUT_FILE="exe_lambda"
OUTPUT_FLAG=-o $(OUTPUT_FILE)
WARNINGS_FLAG=-Wall -Werror
CPPFLAGS=$(STANDARD_FLAG) $(OUTPUT_FLAG) $(WARNINGS_FLAG)
CC=g++
SOURCE_CODE=lambdas.cc
all:
$(CC) $(CPPFLAGS) $(SOURCE_CODE)
run: all
./$(OUTPUT_FILE)
Output is
Print the created vector 0 0 0 0 0 0 0 0 0 0
Doing some operations in the vector 5 10 15 20 25 30 35 40 45 50
Printing using for_each and unary_function
5 10 15 20 25 30 35 40 45 50
Printing and increasing values of the passed integers. This will not change the sequence as the values are passed by value.
CurrentVal(5) ChangedVal(6) CurrentVal(10) ChangedVal(11) CurrentVal(15) ChangedVal(16) CurrentVal(20) ChangedVal(21) CurrentVal(25) ChangedVal(26) CurrentVal(30) ChangedVal(31) CurrentVal(35) ChangedVal(36) CurrentVal(40) ChangedVal(41) CurrentVal(45) ChangedVal(46) CurrentVal(50) ChangedVal(51)
Printing to check if the values changed.
5 10 15 20 25 30 35 40 45 50
Printing and increasing values of the passed integers. This will CHANGE the values as we are passing the numbers by reference.
CurrentVal(5) ChangedVal(6) CurrentVal(10) ChangedVal(11) CurrentVal(15) ChangedVal(16) CurrentVal(20) ChangedVal(21) CurrentVal(25) ChangedVal(26) CurrentVal(30) ChangedVal(31) CurrentVal(35) ChangedVal(36) CurrentVal(40) ChangedVal(41) CurrentVal(45) ChangedVal(46) CurrentVal(50) ChangedVal(51)
Printing to check if the values changed.
6 11 16 21 26 31 36 41 46 51
Increasing values of the passed integers in the vector. This will CHANGE the values as we are passing the numbers by reference. This time we are also passing the value with which we want to increase.
CurrentVal(6) ChangedVal(11) CurrentVal(11) ChangedVal(16) CurrentVal(16) ChangedVal(21) CurrentVal(21) ChangedVal(26) CurrentVal(26) ChangedVal(31) CurrentVal(31) ChangedVal(36) CurrentVal(36) ChangedVal(41) CurrentVal(41) ChangedVal(46) CurrentVal(46) ChangedVal(51) CurrentVal(51) ChangedVal(56)
Printing to check if the values changed.
11 16 21 26 31 36 41 46 51 56
Converting all the odd numbers to even by increasing by 1. This will CHANGE the values as we are passing the numbers by reference.
Printing to check if the values changedX.
12 16 22 26 32 36 42 46 52 56
Printing to check if the numbers are sorted.
12 16 22 26 32 36 42 46 52 56
Removing all the numbers which are divisible by 4
Printing to check if the numbers are removed.
22 26 42 46
Adding some more elements
Printing the freshly added numbers 22 26 42 46 10 20 30 40 50
Printing to check if 22 was removed. We are counting the presence of the number 22 in the vector. If it is not 0, we exit.
26 42 46 10 20 30 40 50
Printing the shuffled vector.
10 30 46 20 26 40 50 42
Printing after replacing 50 with -1
10 30 46 20 26 40 -1 42
Printing after replacing max element with 100
10 30 100 20 26 40 -1 42
Our max is 2147483647
c++ lambda
 |Â
show 4 more comments
up vote
4
down vote
favorite
I have written a cpp program which demonstrates the use of the following functionalities in modern cpp.
Lambda Functions
std::generate
std::vector
std::erase
std::remove_if
std::remove
std::max_element
std::for_each
std::shuffle
I want to understand the following
(1) Have I written the code properly or there are somethings which needs to be improved.
(2) Will it be helpful if I write it as a blog for others. If yes, do I need to add more comments etc to make it more consumable?
/*
* Copyright Rishi Agrawal <rishi.b.agrawal@gmail.com>
*
* The idea behind this program is to understand how to use the following.
* Lambda Functions
* std::generate
* std::vector
* std::erase
* std::remove_if
* std::remove
* std::max_element
* std::for_each
* std::shuffle
*/
#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
#include <cassert>
void printInt(int n)
std::cout << " " << n;
/**
* @brief Function to demonstrate lambda functions.
*
* @param v - the vector to use.
*/
void playingWithLambdaFunctions(std::vector<int> &v)
/* Generate the elements in the vector. The lambda function take a variable
* and increments it everytime. Using mutable so that the value of the
* variable is preserved accross invocations of lambda.*/
std::generate(v.begin(), v.end(), [n = 0]() mutable n = n + 5; return n;);
/* Print the vector using a lambda function. Here the value at a particular
* position is passed as n. This passing is by value. */
std::for_each(v.begin(), v.end(), (int n) std::cout << " " << n; );
/* Other way of printing where we use a unary function for printing. */
std::cerr << "nnPrinting using for_each and unary_functionnn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnPrinting and increasing values of the passed integers. "
"This will not change the sequence as the values are "
"passed by value.nn";
std::for_each(v.begin(), v.end(), (int n)
std::cout << " CurrentVal(" << n << ")";
n = n + 1; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
std::cerr << "nnPrinting to check if the values changed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnPrinting and increasing values of the passed integers. "
"This will CHANGE the values as we are passing the "
"numbers by reference.nn";
std::for_each(v.begin(), v.end(), (int &n)
std::cout << " CurrentVal(" << n << ")";
n = n + 1; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
std::cerr << "nnPrinting to check if the values changed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnIncreasing values of the passed integers in the vector. "
"This will CHANGE the values as we are passing the "
"numbers by reference. This time we are also passing the "
"value with which we want to increase.nn";
int increment = 5;
std::for_each(v.begin(), v.end(), [increment](int &n)
std::cout << " CurrentVal(" << n << ")";
n = n + increment; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
std::cerr << "nnPrinting to check if the values changed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnConverting all the odd numbers to even by increasing by 1."
" This will CHANGE the values as we are passing the "
"numbers by reference.nn";
std::for_each(v.begin(), v.end(), (int &n) if (n%2) n++; );
std::cerr << "nnPrinting to check if the values changedX.nn";
std::for_each(v.begin(), v.end(), printInt);
/**
* @brief Do some more operations like remove_if, and remove on vector.
*
* @param v - the vector to use.
*/
void otherSequenceOperations(std::vector<int> &v)
/* Remove the elements which are divisible by 4 */
std::sort(v.begin(), v.end());
std::cerr << "nnPrinting to check if the numbers are sorted.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "nnRemoving all the numbers which are divisible by 4";
auto eraseBegin = std::remove_if(v.begin(), v.end(), (const int n)
if (n%4 == 0)
return true;
else
return false;
);
/* std::remove_if moves the removable elements to the end of the list and
* returns the iterator to the begining of the elements to be removed. */
v.erase(eraseBegin, v.end());
std::cerr << "nnPrinting to check if the numbers are removed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "nAdding some more elements";
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
std::cout << "nPrinting the freshly added numbers";
std::for_each(v.begin(), v.end(), printInt);
/* Remove the elements which is equal to 22. */
int numberToRemove = 22;
eraseBegin = std::remove(v.begin(), v.end(), numberToRemove);
v.erase(eraseBegin, v.end());
std::cerr << "nnPrinting to check if 22 was removed. We are counting the "
"presence of the number 22 in the vector. If it is not 0, we "
" exit.nn";
assert(0 == count(v.begin(), v.end(), numberToRemove));
std::for_each(v.begin(), v.end(), printInt);
/**
* @brief Function to demonstrate the std::max_element.
*
* @param v - the vector to be used.
*/
void playWithMaxElement(std::vector <int> &v)
auto maxElementIt = std::max_element(v.begin(), v.end());
auto maxElement = *(maxElementIt);
/* Replace the max element with -1.*/
std::replace(v.begin(), v.end(), maxElement, -1);
std::cout << "nnPrinting after replacing " << maxElement << " with "
<< -1 << "n";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "n";
/* Replace the max element in one line. */
std::replace(v.begin(),
v.end(),
*(std::max_element(v.begin(), v.end())), // Return the position
// of the max element.
100);
std::cout << "nnPrinting after replacing max element with 100 n";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "n";
/* Writing our max function */
int ourMax = 0;
v.push_back(std::numeric_limits<int>::max());
std::for_each(v.begin(), v.end(), [&ourMax](int n)
if (n > ourMax)
ourMax = n;
);
std::cerr << "nOur max is " << ourMax;
assert(ourMax == std::numeric_limits<int>::max());
/**
* @brief Shuffles the vector
*
* @param v - the vector to be shuffled.
*/
void shuffleVector(std::vector <int> &v)
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
std::cerr << "nnPrinting the shuffled vector.nn";
std::for_each(v.begin(), v.end(), printInt);
int main()
int sizeOfVector = 10;
/* Create the vector. */
std::vector <int> v = std::vector <int>(sizeOfVector);
std::cout << "nPrint the created vector";
std::for_each(v.begin(), v.end(), printInt);
std::cout <<"nDoing some operations in the vector";
playingWithLambdaFunctions(v);
otherSequenceOperations(v);
shuffleVector(v);
playWithMaxElement(v);
return 0;
Makefile is
CPP_STANDARD="c++17"
STANDARD_FLAG="-std=$(CPP_STANDARD)"
OUTPUT_FILE="exe_lambda"
OUTPUT_FLAG=-o $(OUTPUT_FILE)
WARNINGS_FLAG=-Wall -Werror
CPPFLAGS=$(STANDARD_FLAG) $(OUTPUT_FLAG) $(WARNINGS_FLAG)
CC=g++
SOURCE_CODE=lambdas.cc
all:
$(CC) $(CPPFLAGS) $(SOURCE_CODE)
run: all
./$(OUTPUT_FILE)
Output is
Print the created vector 0 0 0 0 0 0 0 0 0 0
Doing some operations in the vector 5 10 15 20 25 30 35 40 45 50
Printing using for_each and unary_function
5 10 15 20 25 30 35 40 45 50
Printing and increasing values of the passed integers. This will not change the sequence as the values are passed by value.
CurrentVal(5) ChangedVal(6) CurrentVal(10) ChangedVal(11) CurrentVal(15) ChangedVal(16) CurrentVal(20) ChangedVal(21) CurrentVal(25) ChangedVal(26) CurrentVal(30) ChangedVal(31) CurrentVal(35) ChangedVal(36) CurrentVal(40) ChangedVal(41) CurrentVal(45) ChangedVal(46) CurrentVal(50) ChangedVal(51)
Printing to check if the values changed.
5 10 15 20 25 30 35 40 45 50
Printing and increasing values of the passed integers. This will CHANGE the values as we are passing the numbers by reference.
CurrentVal(5) ChangedVal(6) CurrentVal(10) ChangedVal(11) CurrentVal(15) ChangedVal(16) CurrentVal(20) ChangedVal(21) CurrentVal(25) ChangedVal(26) CurrentVal(30) ChangedVal(31) CurrentVal(35) ChangedVal(36) CurrentVal(40) ChangedVal(41) CurrentVal(45) ChangedVal(46) CurrentVal(50) ChangedVal(51)
Printing to check if the values changed.
6 11 16 21 26 31 36 41 46 51
Increasing values of the passed integers in the vector. This will CHANGE the values as we are passing the numbers by reference. This time we are also passing the value with which we want to increase.
CurrentVal(6) ChangedVal(11) CurrentVal(11) ChangedVal(16) CurrentVal(16) ChangedVal(21) CurrentVal(21) ChangedVal(26) CurrentVal(26) ChangedVal(31) CurrentVal(31) ChangedVal(36) CurrentVal(36) ChangedVal(41) CurrentVal(41) ChangedVal(46) CurrentVal(46) ChangedVal(51) CurrentVal(51) ChangedVal(56)
Printing to check if the values changed.
11 16 21 26 31 36 41 46 51 56
Converting all the odd numbers to even by increasing by 1. This will CHANGE the values as we are passing the numbers by reference.
Printing to check if the values changedX.
12 16 22 26 32 36 42 46 52 56
Printing to check if the numbers are sorted.
12 16 22 26 32 36 42 46 52 56
Removing all the numbers which are divisible by 4
Printing to check if the numbers are removed.
22 26 42 46
Adding some more elements
Printing the freshly added numbers 22 26 42 46 10 20 30 40 50
Printing to check if 22 was removed. We are counting the presence of the number 22 in the vector. If it is not 0, we exit.
26 42 46 10 20 30 40 50
Printing the shuffled vector.
10 30 46 20 26 40 50 42
Printing after replacing 50 with -1
10 30 46 20 26 40 -1 42
Printing after replacing max element with 100
10 30 100 20 26 40 -1 42
Our max is 2147483647
c++ lambda
2
Which version of C++ are you targeting?
â nwp
Apr 17 at 12:48
You usestd:for_each
way too much.for (auto& elem: vec) ...
is better unless: 1)for_each
's last argument is an existing function (likestd::for_each(v.begin(), v.end(), printInt);
) or 2) you want to iterate over n elements :std::for_each(v.begin(), v.begin()+3, (auto i) std::cout << i*i; );
â papagaga
Apr 17 at 13:49
A blog on<algorithm>
isn't a bad idea, but you must aim for something more consistent than these examples, e.g: which king of "raw loops" you can replace with algorithms, which algorithm you should choose, etc.
â papagaga
Apr 17 at 13:53
I notice the copyright notice in your code. Which is fine. But I should also note that by posting on this site you are granting a license for the code to be used (see the bottom of the page)contributions licensed under cc by-sa 3.0
Link: cc by-sa 3.0
â Martin York
Apr 17 at 15:10
Sure you can write an article about these. But you are missing the more important algorithms.std::find()
andstd::transform()
. Thestd::for_each()
has been made a bit redundant withrange based for
. But I think you would be missing the point by just talking about these. Its the combination of algorithm with iterator that makes them interesting. Look at some of the interesting iterators (not just the container iterators)std::istream_iterator
andstd::ostream_iterator
â Martin York
Apr 17 at 15:15
 |Â
show 4 more comments
up vote
4
down vote
favorite
up vote
4
down vote
favorite
I have written a cpp program which demonstrates the use of the following functionalities in modern cpp.
Lambda Functions
std::generate
std::vector
std::erase
std::remove_if
std::remove
std::max_element
std::for_each
std::shuffle
I want to understand the following
(1) Have I written the code properly or there are somethings which needs to be improved.
(2) Will it be helpful if I write it as a blog for others. If yes, do I need to add more comments etc to make it more consumable?
/*
* Copyright Rishi Agrawal <rishi.b.agrawal@gmail.com>
*
* The idea behind this program is to understand how to use the following.
* Lambda Functions
* std::generate
* std::vector
* std::erase
* std::remove_if
* std::remove
* std::max_element
* std::for_each
* std::shuffle
*/
#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
#include <cassert>
void printInt(int n)
std::cout << " " << n;
/**
* @brief Function to demonstrate lambda functions.
*
* @param v - the vector to use.
*/
void playingWithLambdaFunctions(std::vector<int> &v)
/* Generate the elements in the vector. The lambda function take a variable
* and increments it everytime. Using mutable so that the value of the
* variable is preserved accross invocations of lambda.*/
std::generate(v.begin(), v.end(), [n = 0]() mutable n = n + 5; return n;);
/* Print the vector using a lambda function. Here the value at a particular
* position is passed as n. This passing is by value. */
std::for_each(v.begin(), v.end(), (int n) std::cout << " " << n; );
/* Other way of printing where we use a unary function for printing. */
std::cerr << "nnPrinting using for_each and unary_functionnn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnPrinting and increasing values of the passed integers. "
"This will not change the sequence as the values are "
"passed by value.nn";
std::for_each(v.begin(), v.end(), (int n)
std::cout << " CurrentVal(" << n << ")";
n = n + 1; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
std::cerr << "nnPrinting to check if the values changed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnPrinting and increasing values of the passed integers. "
"This will CHANGE the values as we are passing the "
"numbers by reference.nn";
std::for_each(v.begin(), v.end(), (int &n)
std::cout << " CurrentVal(" << n << ")";
n = n + 1; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
std::cerr << "nnPrinting to check if the values changed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnIncreasing values of the passed integers in the vector. "
"This will CHANGE the values as we are passing the "
"numbers by reference. This time we are also passing the "
"value with which we want to increase.nn";
int increment = 5;
std::for_each(v.begin(), v.end(), [increment](int &n)
std::cout << " CurrentVal(" << n << ")";
n = n + increment; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
std::cerr << "nnPrinting to check if the values changed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnConverting all the odd numbers to even by increasing by 1."
" This will CHANGE the values as we are passing the "
"numbers by reference.nn";
std::for_each(v.begin(), v.end(), (int &n) if (n%2) n++; );
std::cerr << "nnPrinting to check if the values changedX.nn";
std::for_each(v.begin(), v.end(), printInt);
/**
* @brief Do some more operations like remove_if, and remove on vector.
*
* @param v - the vector to use.
*/
void otherSequenceOperations(std::vector<int> &v)
/* Remove the elements which are divisible by 4 */
std::sort(v.begin(), v.end());
std::cerr << "nnPrinting to check if the numbers are sorted.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "nnRemoving all the numbers which are divisible by 4";
auto eraseBegin = std::remove_if(v.begin(), v.end(), (const int n)
if (n%4 == 0)
return true;
else
return false;
);
/* std::remove_if moves the removable elements to the end of the list and
* returns the iterator to the begining of the elements to be removed. */
v.erase(eraseBegin, v.end());
std::cerr << "nnPrinting to check if the numbers are removed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "nAdding some more elements";
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
std::cout << "nPrinting the freshly added numbers";
std::for_each(v.begin(), v.end(), printInt);
/* Remove the elements which is equal to 22. */
int numberToRemove = 22;
eraseBegin = std::remove(v.begin(), v.end(), numberToRemove);
v.erase(eraseBegin, v.end());
std::cerr << "nnPrinting to check if 22 was removed. We are counting the "
"presence of the number 22 in the vector. If it is not 0, we "
" exit.nn";
assert(0 == count(v.begin(), v.end(), numberToRemove));
std::for_each(v.begin(), v.end(), printInt);
/**
* @brief Function to demonstrate the std::max_element.
*
* @param v - the vector to be used.
*/
void playWithMaxElement(std::vector <int> &v)
auto maxElementIt = std::max_element(v.begin(), v.end());
auto maxElement = *(maxElementIt);
/* Replace the max element with -1.*/
std::replace(v.begin(), v.end(), maxElement, -1);
std::cout << "nnPrinting after replacing " << maxElement << " with "
<< -1 << "n";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "n";
/* Replace the max element in one line. */
std::replace(v.begin(),
v.end(),
*(std::max_element(v.begin(), v.end())), // Return the position
// of the max element.
100);
std::cout << "nnPrinting after replacing max element with 100 n";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "n";
/* Writing our max function */
int ourMax = 0;
v.push_back(std::numeric_limits<int>::max());
std::for_each(v.begin(), v.end(), [&ourMax](int n)
if (n > ourMax)
ourMax = n;
);
std::cerr << "nOur max is " << ourMax;
assert(ourMax == std::numeric_limits<int>::max());
/**
* @brief Shuffles the vector
*
* @param v - the vector to be shuffled.
*/
void shuffleVector(std::vector <int> &v)
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
std::cerr << "nnPrinting the shuffled vector.nn";
std::for_each(v.begin(), v.end(), printInt);
int main()
int sizeOfVector = 10;
/* Create the vector. */
std::vector <int> v = std::vector <int>(sizeOfVector);
std::cout << "nPrint the created vector";
std::for_each(v.begin(), v.end(), printInt);
std::cout <<"nDoing some operations in the vector";
playingWithLambdaFunctions(v);
otherSequenceOperations(v);
shuffleVector(v);
playWithMaxElement(v);
return 0;
Makefile is
CPP_STANDARD="c++17"
STANDARD_FLAG="-std=$(CPP_STANDARD)"
OUTPUT_FILE="exe_lambda"
OUTPUT_FLAG=-o $(OUTPUT_FILE)
WARNINGS_FLAG=-Wall -Werror
CPPFLAGS=$(STANDARD_FLAG) $(OUTPUT_FLAG) $(WARNINGS_FLAG)
CC=g++
SOURCE_CODE=lambdas.cc
all:
$(CC) $(CPPFLAGS) $(SOURCE_CODE)
run: all
./$(OUTPUT_FILE)
Output is
Print the created vector 0 0 0 0 0 0 0 0 0 0
Doing some operations in the vector 5 10 15 20 25 30 35 40 45 50
Printing using for_each and unary_function
5 10 15 20 25 30 35 40 45 50
Printing and increasing values of the passed integers. This will not change the sequence as the values are passed by value.
CurrentVal(5) ChangedVal(6) CurrentVal(10) ChangedVal(11) CurrentVal(15) ChangedVal(16) CurrentVal(20) ChangedVal(21) CurrentVal(25) ChangedVal(26) CurrentVal(30) ChangedVal(31) CurrentVal(35) ChangedVal(36) CurrentVal(40) ChangedVal(41) CurrentVal(45) ChangedVal(46) CurrentVal(50) ChangedVal(51)
Printing to check if the values changed.
5 10 15 20 25 30 35 40 45 50
Printing and increasing values of the passed integers. This will CHANGE the values as we are passing the numbers by reference.
CurrentVal(5) ChangedVal(6) CurrentVal(10) ChangedVal(11) CurrentVal(15) ChangedVal(16) CurrentVal(20) ChangedVal(21) CurrentVal(25) ChangedVal(26) CurrentVal(30) ChangedVal(31) CurrentVal(35) ChangedVal(36) CurrentVal(40) ChangedVal(41) CurrentVal(45) ChangedVal(46) CurrentVal(50) ChangedVal(51)
Printing to check if the values changed.
6 11 16 21 26 31 36 41 46 51
Increasing values of the passed integers in the vector. This will CHANGE the values as we are passing the numbers by reference. This time we are also passing the value with which we want to increase.
CurrentVal(6) ChangedVal(11) CurrentVal(11) ChangedVal(16) CurrentVal(16) ChangedVal(21) CurrentVal(21) ChangedVal(26) CurrentVal(26) ChangedVal(31) CurrentVal(31) ChangedVal(36) CurrentVal(36) ChangedVal(41) CurrentVal(41) ChangedVal(46) CurrentVal(46) ChangedVal(51) CurrentVal(51) ChangedVal(56)
Printing to check if the values changed.
11 16 21 26 31 36 41 46 51 56
Converting all the odd numbers to even by increasing by 1. This will CHANGE the values as we are passing the numbers by reference.
Printing to check if the values changedX.
12 16 22 26 32 36 42 46 52 56
Printing to check if the numbers are sorted.
12 16 22 26 32 36 42 46 52 56
Removing all the numbers which are divisible by 4
Printing to check if the numbers are removed.
22 26 42 46
Adding some more elements
Printing the freshly added numbers 22 26 42 46 10 20 30 40 50
Printing to check if 22 was removed. We are counting the presence of the number 22 in the vector. If it is not 0, we exit.
26 42 46 10 20 30 40 50
Printing the shuffled vector.
10 30 46 20 26 40 50 42
Printing after replacing 50 with -1
10 30 46 20 26 40 -1 42
Printing after replacing max element with 100
10 30 100 20 26 40 -1 42
Our max is 2147483647
c++ lambda
I have written a cpp program which demonstrates the use of the following functionalities in modern cpp.
Lambda Functions
std::generate
std::vector
std::erase
std::remove_if
std::remove
std::max_element
std::for_each
std::shuffle
I want to understand the following
(1) Have I written the code properly or there are somethings which needs to be improved.
(2) Will it be helpful if I write it as a blog for others. If yes, do I need to add more comments etc to make it more consumable?
/*
* Copyright Rishi Agrawal <rishi.b.agrawal@gmail.com>
*
* The idea behind this program is to understand how to use the following.
* Lambda Functions
* std::generate
* std::vector
* std::erase
* std::remove_if
* std::remove
* std::max_element
* std::for_each
* std::shuffle
*/
#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
#include <cassert>
void printInt(int n)
std::cout << " " << n;
/**
* @brief Function to demonstrate lambda functions.
*
* @param v - the vector to use.
*/
void playingWithLambdaFunctions(std::vector<int> &v)
/* Generate the elements in the vector. The lambda function take a variable
* and increments it everytime. Using mutable so that the value of the
* variable is preserved accross invocations of lambda.*/
std::generate(v.begin(), v.end(), [n = 0]() mutable n = n + 5; return n;);
/* Print the vector using a lambda function. Here the value at a particular
* position is passed as n. This passing is by value. */
std::for_each(v.begin(), v.end(), (int n) std::cout << " " << n; );
/* Other way of printing where we use a unary function for printing. */
std::cerr << "nnPrinting using for_each and unary_functionnn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnPrinting and increasing values of the passed integers. "
"This will not change the sequence as the values are "
"passed by value.nn";
std::for_each(v.begin(), v.end(), (int n)
std::cout << " CurrentVal(" << n << ")";
n = n + 1; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
std::cerr << "nnPrinting to check if the values changed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnPrinting and increasing values of the passed integers. "
"This will CHANGE the values as we are passing the "
"numbers by reference.nn";
std::for_each(v.begin(), v.end(), (int &n)
std::cout << " CurrentVal(" << n << ")";
n = n + 1; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
std::cerr << "nnPrinting to check if the values changed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnIncreasing values of the passed integers in the vector. "
"This will CHANGE the values as we are passing the "
"numbers by reference. This time we are also passing the "
"value with which we want to increase.nn";
int increment = 5;
std::for_each(v.begin(), v.end(), [increment](int &n)
std::cout << " CurrentVal(" << n << ")";
n = n + increment; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
std::cerr << "nnPrinting to check if the values changed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cerr << "nnConverting all the odd numbers to even by increasing by 1."
" This will CHANGE the values as we are passing the "
"numbers by reference.nn";
std::for_each(v.begin(), v.end(), (int &n) if (n%2) n++; );
std::cerr << "nnPrinting to check if the values changedX.nn";
std::for_each(v.begin(), v.end(), printInt);
/**
* @brief Do some more operations like remove_if, and remove on vector.
*
* @param v - the vector to use.
*/
void otherSequenceOperations(std::vector<int> &v)
/* Remove the elements which are divisible by 4 */
std::sort(v.begin(), v.end());
std::cerr << "nnPrinting to check if the numbers are sorted.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "nnRemoving all the numbers which are divisible by 4";
auto eraseBegin = std::remove_if(v.begin(), v.end(), (const int n)
if (n%4 == 0)
return true;
else
return false;
);
/* std::remove_if moves the removable elements to the end of the list and
* returns the iterator to the begining of the elements to be removed. */
v.erase(eraseBegin, v.end());
std::cerr << "nnPrinting to check if the numbers are removed.nn";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "nAdding some more elements";
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
std::cout << "nPrinting the freshly added numbers";
std::for_each(v.begin(), v.end(), printInt);
/* Remove the elements which is equal to 22. */
int numberToRemove = 22;
eraseBegin = std::remove(v.begin(), v.end(), numberToRemove);
v.erase(eraseBegin, v.end());
std::cerr << "nnPrinting to check if 22 was removed. We are counting the "
"presence of the number 22 in the vector. If it is not 0, we "
" exit.nn";
assert(0 == count(v.begin(), v.end(), numberToRemove));
std::for_each(v.begin(), v.end(), printInt);
/**
* @brief Function to demonstrate the std::max_element.
*
* @param v - the vector to be used.
*/
void playWithMaxElement(std::vector <int> &v)
auto maxElementIt = std::max_element(v.begin(), v.end());
auto maxElement = *(maxElementIt);
/* Replace the max element with -1.*/
std::replace(v.begin(), v.end(), maxElement, -1);
std::cout << "nnPrinting after replacing " << maxElement << " with "
<< -1 << "n";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "n";
/* Replace the max element in one line. */
std::replace(v.begin(),
v.end(),
*(std::max_element(v.begin(), v.end())), // Return the position
// of the max element.
100);
std::cout << "nnPrinting after replacing max element with 100 n";
std::for_each(v.begin(), v.end(), printInt);
std::cout << "n";
/* Writing our max function */
int ourMax = 0;
v.push_back(std::numeric_limits<int>::max());
std::for_each(v.begin(), v.end(), [&ourMax](int n)
if (n > ourMax)
ourMax = n;
);
std::cerr << "nOur max is " << ourMax;
assert(ourMax == std::numeric_limits<int>::max());
/**
* @brief Shuffles the vector
*
* @param v - the vector to be shuffled.
*/
void shuffleVector(std::vector <int> &v)
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
std::cerr << "nnPrinting the shuffled vector.nn";
std::for_each(v.begin(), v.end(), printInt);
int main()
int sizeOfVector = 10;
/* Create the vector. */
std::vector <int> v = std::vector <int>(sizeOfVector);
std::cout << "nPrint the created vector";
std::for_each(v.begin(), v.end(), printInt);
std::cout <<"nDoing some operations in the vector";
playingWithLambdaFunctions(v);
otherSequenceOperations(v);
shuffleVector(v);
playWithMaxElement(v);
return 0;
Makefile is
CPP_STANDARD="c++17"
STANDARD_FLAG="-std=$(CPP_STANDARD)"
OUTPUT_FILE="exe_lambda"
OUTPUT_FLAG=-o $(OUTPUT_FILE)
WARNINGS_FLAG=-Wall -Werror
CPPFLAGS=$(STANDARD_FLAG) $(OUTPUT_FLAG) $(WARNINGS_FLAG)
CC=g++
SOURCE_CODE=lambdas.cc
all:
$(CC) $(CPPFLAGS) $(SOURCE_CODE)
run: all
./$(OUTPUT_FILE)
Output is
Print the created vector 0 0 0 0 0 0 0 0 0 0
Doing some operations in the vector 5 10 15 20 25 30 35 40 45 50
Printing using for_each and unary_function
5 10 15 20 25 30 35 40 45 50
Printing and increasing values of the passed integers. This will not change the sequence as the values are passed by value.
CurrentVal(5) ChangedVal(6) CurrentVal(10) ChangedVal(11) CurrentVal(15) ChangedVal(16) CurrentVal(20) ChangedVal(21) CurrentVal(25) ChangedVal(26) CurrentVal(30) ChangedVal(31) CurrentVal(35) ChangedVal(36) CurrentVal(40) ChangedVal(41) CurrentVal(45) ChangedVal(46) CurrentVal(50) ChangedVal(51)
Printing to check if the values changed.
5 10 15 20 25 30 35 40 45 50
Printing and increasing values of the passed integers. This will CHANGE the values as we are passing the numbers by reference.
CurrentVal(5) ChangedVal(6) CurrentVal(10) ChangedVal(11) CurrentVal(15) ChangedVal(16) CurrentVal(20) ChangedVal(21) CurrentVal(25) ChangedVal(26) CurrentVal(30) ChangedVal(31) CurrentVal(35) ChangedVal(36) CurrentVal(40) ChangedVal(41) CurrentVal(45) ChangedVal(46) CurrentVal(50) ChangedVal(51)
Printing to check if the values changed.
6 11 16 21 26 31 36 41 46 51
Increasing values of the passed integers in the vector. This will CHANGE the values as we are passing the numbers by reference. This time we are also passing the value with which we want to increase.
CurrentVal(6) ChangedVal(11) CurrentVal(11) ChangedVal(16) CurrentVal(16) ChangedVal(21) CurrentVal(21) ChangedVal(26) CurrentVal(26) ChangedVal(31) CurrentVal(31) ChangedVal(36) CurrentVal(36) ChangedVal(41) CurrentVal(41) ChangedVal(46) CurrentVal(46) ChangedVal(51) CurrentVal(51) ChangedVal(56)
Printing to check if the values changed.
11 16 21 26 31 36 41 46 51 56
Converting all the odd numbers to even by increasing by 1. This will CHANGE the values as we are passing the numbers by reference.
Printing to check if the values changedX.
12 16 22 26 32 36 42 46 52 56
Printing to check if the numbers are sorted.
12 16 22 26 32 36 42 46 52 56
Removing all the numbers which are divisible by 4
Printing to check if the numbers are removed.
22 26 42 46
Adding some more elements
Printing the freshly added numbers 22 26 42 46 10 20 30 40 50
Printing to check if 22 was removed. We are counting the presence of the number 22 in the vector. If it is not 0, we exit.
26 42 46 10 20 30 40 50
Printing the shuffled vector.
10 30 46 20 26 40 50 42
Printing after replacing 50 with -1
10 30 46 20 26 40 -1 42
Printing after replacing max element with 100
10 30 100 20 26 40 -1 42
Our max is 2147483647
c++ lambda
edited Apr 17 at 12:44
asked Apr 17 at 12:33
Rishi Agrawal
385
385
2
Which version of C++ are you targeting?
â nwp
Apr 17 at 12:48
You usestd:for_each
way too much.for (auto& elem: vec) ...
is better unless: 1)for_each
's last argument is an existing function (likestd::for_each(v.begin(), v.end(), printInt);
) or 2) you want to iterate over n elements :std::for_each(v.begin(), v.begin()+3, (auto i) std::cout << i*i; );
â papagaga
Apr 17 at 13:49
A blog on<algorithm>
isn't a bad idea, but you must aim for something more consistent than these examples, e.g: which king of "raw loops" you can replace with algorithms, which algorithm you should choose, etc.
â papagaga
Apr 17 at 13:53
I notice the copyright notice in your code. Which is fine. But I should also note that by posting on this site you are granting a license for the code to be used (see the bottom of the page)contributions licensed under cc by-sa 3.0
Link: cc by-sa 3.0
â Martin York
Apr 17 at 15:10
Sure you can write an article about these. But you are missing the more important algorithms.std::find()
andstd::transform()
. Thestd::for_each()
has been made a bit redundant withrange based for
. But I think you would be missing the point by just talking about these. Its the combination of algorithm with iterator that makes them interesting. Look at some of the interesting iterators (not just the container iterators)std::istream_iterator
andstd::ostream_iterator
â Martin York
Apr 17 at 15:15
 |Â
show 4 more comments
2
Which version of C++ are you targeting?
â nwp
Apr 17 at 12:48
You usestd:for_each
way too much.for (auto& elem: vec) ...
is better unless: 1)for_each
's last argument is an existing function (likestd::for_each(v.begin(), v.end(), printInt);
) or 2) you want to iterate over n elements :std::for_each(v.begin(), v.begin()+3, (auto i) std::cout << i*i; );
â papagaga
Apr 17 at 13:49
A blog on<algorithm>
isn't a bad idea, but you must aim for something more consistent than these examples, e.g: which king of "raw loops" you can replace with algorithms, which algorithm you should choose, etc.
â papagaga
Apr 17 at 13:53
I notice the copyright notice in your code. Which is fine. But I should also note that by posting on this site you are granting a license for the code to be used (see the bottom of the page)contributions licensed under cc by-sa 3.0
Link: cc by-sa 3.0
â Martin York
Apr 17 at 15:10
Sure you can write an article about these. But you are missing the more important algorithms.std::find()
andstd::transform()
. Thestd::for_each()
has been made a bit redundant withrange based for
. But I think you would be missing the point by just talking about these. Its the combination of algorithm with iterator that makes them interesting. Look at some of the interesting iterators (not just the container iterators)std::istream_iterator
andstd::ostream_iterator
â Martin York
Apr 17 at 15:15
2
2
Which version of C++ are you targeting?
â nwp
Apr 17 at 12:48
Which version of C++ are you targeting?
â nwp
Apr 17 at 12:48
You use
std:for_each
way too much. for (auto& elem: vec) ...
is better unless: 1) for_each
's last argument is an existing function (like std::for_each(v.begin(), v.end(), printInt);
) or 2) you want to iterate over n elements :std::for_each(v.begin(), v.begin()+3, (auto i) std::cout << i*i; );
â papagaga
Apr 17 at 13:49
You use
std:for_each
way too much. for (auto& elem: vec) ...
is better unless: 1) for_each
's last argument is an existing function (like std::for_each(v.begin(), v.end(), printInt);
) or 2) you want to iterate over n elements :std::for_each(v.begin(), v.begin()+3, (auto i) std::cout << i*i; );
â papagaga
Apr 17 at 13:49
A blog on
<algorithm>
isn't a bad idea, but you must aim for something more consistent than these examples, e.g: which king of "raw loops" you can replace with algorithms, which algorithm you should choose, etc.â papagaga
Apr 17 at 13:53
A blog on
<algorithm>
isn't a bad idea, but you must aim for something more consistent than these examples, e.g: which king of "raw loops" you can replace with algorithms, which algorithm you should choose, etc.â papagaga
Apr 17 at 13:53
I notice the copyright notice in your code. Which is fine. But I should also note that by posting on this site you are granting a license for the code to be used (see the bottom of the page)
contributions licensed under cc by-sa 3.0
Link: cc by-sa 3.0â Martin York
Apr 17 at 15:10
I notice the copyright notice in your code. Which is fine. But I should also note that by posting on this site you are granting a license for the code to be used (see the bottom of the page)
contributions licensed under cc by-sa 3.0
Link: cc by-sa 3.0â Martin York
Apr 17 at 15:10
Sure you can write an article about these. But you are missing the more important algorithms.
std::find()
and std::transform()
. The std::for_each()
has been made a bit redundant with range based for
. But I think you would be missing the point by just talking about these. Its the combination of algorithm with iterator that makes them interesting. Look at some of the interesting iterators (not just the container iterators) std::istream_iterator
and std::ostream_iterator
â Martin York
Apr 17 at 15:15
Sure you can write an article about these. But you are missing the more important algorithms.
std::find()
and std::transform()
. The std::for_each()
has been made a bit redundant with range based for
. But I think you would be missing the point by just talking about these. Its the combination of algorithm with iterator that makes them interesting. Look at some of the interesting iterators (not just the container iterators) std::istream_iterator
and std::ostream_iterator
â Martin York
Apr 17 at 15:15
 |Â
show 4 more comments
1 Answer
1
active
oldest
votes
up vote
5
down vote
accepted
For such a simple case this Makefile is a waste.
It can be replaced with:
> rm Makefile
> export CXXFLAGS ="-std=c++17 -Wall -Werror"
> make lambdas
The standard implicit rules of Make will build lambdas
from lambdas.cc
Sure Good use:
std::generate(v.begin(), v.end(), [n = 0]() mutable n = n + 5; return n;);
Probably not a good example:
std::for_each(v.begin(), v.end(),
(int n) std::cout << " " << n; );
I like (as it shows intent better).
std::copy(v.begin(), v.end(),
std::ostream_iterator<int>(std::cout, "n");
But I think the modern (and idiomatic) form is:
for(auto const& item: v)
std::cout << v << "n";
I like this even less:
std::for_each(v.begin(), v.end(), printInt);
You could have just as easily written:
printVect(v);
Here the lambda is too large. At this size you should be creating a functor. If you have to do it inline then don't indent it all the way to the right like that. Some people don't have wide screens.
std::for_each(v.begin(), v.end(), (int n)
std::cout << " CurrentVal(" << n << ")";
n = n + 1; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
OK. I'll ignore the rest of the for_each
as I think we have covered the main points.
Good:
std::sort(v.begin(), v.end());
Erase/Remove is a good example. Though this lambda is terrible.
auto eraseBegin = std::remove_if(v.begin(), v.end(), (const int n)
if (n%4 == 0)
return true;
else
return false;
);
Don't use a if statement
to generate a true/false result. That value is an inherent part of the expression.
if (n%4 == 0)
return true;
else
return false;
Can be simplified to:
return n%4 == 0;
Now that's a good lambda.
auto eraseBegin = std::remove_if(v.begin(), v.end(),
(const int n) return n%4 == 0;);
v.erase(eraseBegin, v.end());
Good:
eraseBegin = std::remove(v.begin(), v.end(), numberToRemove);
v.erase(eraseBegin, v.end());
Good:
auto maxElementIt = std::max_element(v.begin(), v.end());
auto maxElement = *(maxElementIt);
Good:
std::replace(v.begin(), v.end(), maxElement, -1);
I like this: it's a good simple example of random
usage.
void shuffleVector(std::vector <int> &v)
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
std::cerr << "nnPrinting the shuffled vector.nn";
std::for_each(v.begin(), v.end(), printInt);
That random number generator is very expensive to create. And once you have it up and running, why recreate it each time? So I would make the random number stuff static inside the function:
void shuffleVector(std::vector <int> &v) {
static std::random_device rd;
static std::mt19937 g(rd());
As a side note:
The standard introduced std::begin()
and std::end()
. So you can now use these rather than the member versions. This allows you to generalize the code so it can be used on any container type (including arrays).
using std::begin;
using std::end;
std::for_each(begin(v), end(v), doStuff);
Now you don't need to care about the type of v
. You can even change it to a C-Array and it would still work.
I apologize if I'm wrong but beyond being expensive to create doesn't a PRNG need to be a single reusable instance like you suggested in order to work properly?
â bruglesco
Apr 17 at 22:09
@bruglesco The new random allows you to create multiple random number generators and they should work independently (and I hear well). But in my personal opinion: One should be enough for an app.
â Martin York
Apr 17 at 23:06
DoesnâÂÂt non-memberbegin
andend
need to be unqualified to really be universal?std::begin
will work for a primitive array and std collections, but not for custom collections and ranges from 3rd party libraries that are not in thestd
namespace. You need to use ADL, just like withswap
.
â JDà Âugosz
Apr 18 at 6:30
Thanks a lot for reviewing in so much detail. Thanks for the useful comments. I will incorporate the suggested changes. I got to learn a lot. :-)
â Rishi Agrawal
Apr 18 at 7:24
@JDÃ Âugosz I see what you are saying. Do be honest I had not thought about that, but its a good point. You are saying for types that don't have abegin/end
method but do have specializations of thebegin/end
free standing methods. Personally I would hope that if you implement iterator like semantics for your object you also implement thebegin/end
method, but I can see how it is not required.
â Martin York
Apr 18 at 16:54
 |Â
show 1 more comment
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
5
down vote
accepted
For such a simple case this Makefile is a waste.
It can be replaced with:
> rm Makefile
> export CXXFLAGS ="-std=c++17 -Wall -Werror"
> make lambdas
The standard implicit rules of Make will build lambdas
from lambdas.cc
Sure Good use:
std::generate(v.begin(), v.end(), [n = 0]() mutable n = n + 5; return n;);
Probably not a good example:
std::for_each(v.begin(), v.end(),
(int n) std::cout << " " << n; );
I like (as it shows intent better).
std::copy(v.begin(), v.end(),
std::ostream_iterator<int>(std::cout, "n");
But I think the modern (and idiomatic) form is:
for(auto const& item: v)
std::cout << v << "n";
I like this even less:
std::for_each(v.begin(), v.end(), printInt);
You could have just as easily written:
printVect(v);
Here the lambda is too large. At this size you should be creating a functor. If you have to do it inline then don't indent it all the way to the right like that. Some people don't have wide screens.
std::for_each(v.begin(), v.end(), (int n)
std::cout << " CurrentVal(" << n << ")";
n = n + 1; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
OK. I'll ignore the rest of the for_each
as I think we have covered the main points.
Good:
std::sort(v.begin(), v.end());
Erase/Remove is a good example. Though this lambda is terrible.
auto eraseBegin = std::remove_if(v.begin(), v.end(), (const int n)
if (n%4 == 0)
return true;
else
return false;
);
Don't use a if statement
to generate a true/false result. That value is an inherent part of the expression.
if (n%4 == 0)
return true;
else
return false;
Can be simplified to:
return n%4 == 0;
Now that's a good lambda.
auto eraseBegin = std::remove_if(v.begin(), v.end(),
(const int n) return n%4 == 0;);
v.erase(eraseBegin, v.end());
Good:
eraseBegin = std::remove(v.begin(), v.end(), numberToRemove);
v.erase(eraseBegin, v.end());
Good:
auto maxElementIt = std::max_element(v.begin(), v.end());
auto maxElement = *(maxElementIt);
Good:
std::replace(v.begin(), v.end(), maxElement, -1);
I like this: it's a good simple example of random
usage.
void shuffleVector(std::vector <int> &v)
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
std::cerr << "nnPrinting the shuffled vector.nn";
std::for_each(v.begin(), v.end(), printInt);
That random number generator is very expensive to create. And once you have it up and running, why recreate it each time? So I would make the random number stuff static inside the function:
void shuffleVector(std::vector <int> &v) {
static std::random_device rd;
static std::mt19937 g(rd());
As a side note:
The standard introduced std::begin()
and std::end()
. So you can now use these rather than the member versions. This allows you to generalize the code so it can be used on any container type (including arrays).
using std::begin;
using std::end;
std::for_each(begin(v), end(v), doStuff);
Now you don't need to care about the type of v
. You can even change it to a C-Array and it would still work.
I apologize if I'm wrong but beyond being expensive to create doesn't a PRNG need to be a single reusable instance like you suggested in order to work properly?
â bruglesco
Apr 17 at 22:09
@bruglesco The new random allows you to create multiple random number generators and they should work independently (and I hear well). But in my personal opinion: One should be enough for an app.
â Martin York
Apr 17 at 23:06
DoesnâÂÂt non-memberbegin
andend
need to be unqualified to really be universal?std::begin
will work for a primitive array and std collections, but not for custom collections and ranges from 3rd party libraries that are not in thestd
namespace. You need to use ADL, just like withswap
.
â JDà Âugosz
Apr 18 at 6:30
Thanks a lot for reviewing in so much detail. Thanks for the useful comments. I will incorporate the suggested changes. I got to learn a lot. :-)
â Rishi Agrawal
Apr 18 at 7:24
@JDÃ Âugosz I see what you are saying. Do be honest I had not thought about that, but its a good point. You are saying for types that don't have abegin/end
method but do have specializations of thebegin/end
free standing methods. Personally I would hope that if you implement iterator like semantics for your object you also implement thebegin/end
method, but I can see how it is not required.
â Martin York
Apr 18 at 16:54
 |Â
show 1 more comment
up vote
5
down vote
accepted
For such a simple case this Makefile is a waste.
It can be replaced with:
> rm Makefile
> export CXXFLAGS ="-std=c++17 -Wall -Werror"
> make lambdas
The standard implicit rules of Make will build lambdas
from lambdas.cc
Sure Good use:
std::generate(v.begin(), v.end(), [n = 0]() mutable n = n + 5; return n;);
Probably not a good example:
std::for_each(v.begin(), v.end(),
(int n) std::cout << " " << n; );
I like (as it shows intent better).
std::copy(v.begin(), v.end(),
std::ostream_iterator<int>(std::cout, "n");
But I think the modern (and idiomatic) form is:
for(auto const& item: v)
std::cout << v << "n";
I like this even less:
std::for_each(v.begin(), v.end(), printInt);
You could have just as easily written:
printVect(v);
Here the lambda is too large. At this size you should be creating a functor. If you have to do it inline then don't indent it all the way to the right like that. Some people don't have wide screens.
std::for_each(v.begin(), v.end(), (int n)
std::cout << " CurrentVal(" << n << ")";
n = n + 1; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
OK. I'll ignore the rest of the for_each
as I think we have covered the main points.
Good:
std::sort(v.begin(), v.end());
Erase/Remove is a good example. Though this lambda is terrible.
auto eraseBegin = std::remove_if(v.begin(), v.end(), (const int n)
if (n%4 == 0)
return true;
else
return false;
);
Don't use a if statement
to generate a true/false result. That value is an inherent part of the expression.
if (n%4 == 0)
return true;
else
return false;
Can be simplified to:
return n%4 == 0;
Now that's a good lambda.
auto eraseBegin = std::remove_if(v.begin(), v.end(),
(const int n) return n%4 == 0;);
v.erase(eraseBegin, v.end());
Good:
eraseBegin = std::remove(v.begin(), v.end(), numberToRemove);
v.erase(eraseBegin, v.end());
Good:
auto maxElementIt = std::max_element(v.begin(), v.end());
auto maxElement = *(maxElementIt);
Good:
std::replace(v.begin(), v.end(), maxElement, -1);
I like this: it's a good simple example of random
usage.
void shuffleVector(std::vector <int> &v)
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
std::cerr << "nnPrinting the shuffled vector.nn";
std::for_each(v.begin(), v.end(), printInt);
That random number generator is very expensive to create. And once you have it up and running, why recreate it each time? So I would make the random number stuff static inside the function:
void shuffleVector(std::vector <int> &v) {
static std::random_device rd;
static std::mt19937 g(rd());
As a side note:
The standard introduced std::begin()
and std::end()
. So you can now use these rather than the member versions. This allows you to generalize the code so it can be used on any container type (including arrays).
using std::begin;
using std::end;
std::for_each(begin(v), end(v), doStuff);
Now you don't need to care about the type of v
. You can even change it to a C-Array and it would still work.
I apologize if I'm wrong but beyond being expensive to create doesn't a PRNG need to be a single reusable instance like you suggested in order to work properly?
â bruglesco
Apr 17 at 22:09
@bruglesco The new random allows you to create multiple random number generators and they should work independently (and I hear well). But in my personal opinion: One should be enough for an app.
â Martin York
Apr 17 at 23:06
DoesnâÂÂt non-memberbegin
andend
need to be unqualified to really be universal?std::begin
will work for a primitive array and std collections, but not for custom collections and ranges from 3rd party libraries that are not in thestd
namespace. You need to use ADL, just like withswap
.
â JDà Âugosz
Apr 18 at 6:30
Thanks a lot for reviewing in so much detail. Thanks for the useful comments. I will incorporate the suggested changes. I got to learn a lot. :-)
â Rishi Agrawal
Apr 18 at 7:24
@JDÃ Âugosz I see what you are saying. Do be honest I had not thought about that, but its a good point. You are saying for types that don't have abegin/end
method but do have specializations of thebegin/end
free standing methods. Personally I would hope that if you implement iterator like semantics for your object you also implement thebegin/end
method, but I can see how it is not required.
â Martin York
Apr 18 at 16:54
 |Â
show 1 more comment
up vote
5
down vote
accepted
up vote
5
down vote
accepted
For such a simple case this Makefile is a waste.
It can be replaced with:
> rm Makefile
> export CXXFLAGS ="-std=c++17 -Wall -Werror"
> make lambdas
The standard implicit rules of Make will build lambdas
from lambdas.cc
Sure Good use:
std::generate(v.begin(), v.end(), [n = 0]() mutable n = n + 5; return n;);
Probably not a good example:
std::for_each(v.begin(), v.end(),
(int n) std::cout << " " << n; );
I like (as it shows intent better).
std::copy(v.begin(), v.end(),
std::ostream_iterator<int>(std::cout, "n");
But I think the modern (and idiomatic) form is:
for(auto const& item: v)
std::cout << v << "n";
I like this even less:
std::for_each(v.begin(), v.end(), printInt);
You could have just as easily written:
printVect(v);
Here the lambda is too large. At this size you should be creating a functor. If you have to do it inline then don't indent it all the way to the right like that. Some people don't have wide screens.
std::for_each(v.begin(), v.end(), (int n)
std::cout << " CurrentVal(" << n << ")";
n = n + 1; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
OK. I'll ignore the rest of the for_each
as I think we have covered the main points.
Good:
std::sort(v.begin(), v.end());
Erase/Remove is a good example. Though this lambda is terrible.
auto eraseBegin = std::remove_if(v.begin(), v.end(), (const int n)
if (n%4 == 0)
return true;
else
return false;
);
Don't use a if statement
to generate a true/false result. That value is an inherent part of the expression.
if (n%4 == 0)
return true;
else
return false;
Can be simplified to:
return n%4 == 0;
Now that's a good lambda.
auto eraseBegin = std::remove_if(v.begin(), v.end(),
(const int n) return n%4 == 0;);
v.erase(eraseBegin, v.end());
Good:
eraseBegin = std::remove(v.begin(), v.end(), numberToRemove);
v.erase(eraseBegin, v.end());
Good:
auto maxElementIt = std::max_element(v.begin(), v.end());
auto maxElement = *(maxElementIt);
Good:
std::replace(v.begin(), v.end(), maxElement, -1);
I like this: it's a good simple example of random
usage.
void shuffleVector(std::vector <int> &v)
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
std::cerr << "nnPrinting the shuffled vector.nn";
std::for_each(v.begin(), v.end(), printInt);
That random number generator is very expensive to create. And once you have it up and running, why recreate it each time? So I would make the random number stuff static inside the function:
void shuffleVector(std::vector <int> &v) {
static std::random_device rd;
static std::mt19937 g(rd());
As a side note:
The standard introduced std::begin()
and std::end()
. So you can now use these rather than the member versions. This allows you to generalize the code so it can be used on any container type (including arrays).
using std::begin;
using std::end;
std::for_each(begin(v), end(v), doStuff);
Now you don't need to care about the type of v
. You can even change it to a C-Array and it would still work.
For such a simple case this Makefile is a waste.
It can be replaced with:
> rm Makefile
> export CXXFLAGS ="-std=c++17 -Wall -Werror"
> make lambdas
The standard implicit rules of Make will build lambdas
from lambdas.cc
Sure Good use:
std::generate(v.begin(), v.end(), [n = 0]() mutable n = n + 5; return n;);
Probably not a good example:
std::for_each(v.begin(), v.end(),
(int n) std::cout << " " << n; );
I like (as it shows intent better).
std::copy(v.begin(), v.end(),
std::ostream_iterator<int>(std::cout, "n");
But I think the modern (and idiomatic) form is:
for(auto const& item: v)
std::cout << v << "n";
I like this even less:
std::for_each(v.begin(), v.end(), printInt);
You could have just as easily written:
printVect(v);
Here the lambda is too large. At this size you should be creating a functor. If you have to do it inline then don't indent it all the way to the right like that. Some people don't have wide screens.
std::for_each(v.begin(), v.end(), (int n)
std::cout << " CurrentVal(" << n << ")";
n = n + 1; // Changing the value.
std::cout << " ChangedVal(" << n << ")";
);
OK. I'll ignore the rest of the for_each
as I think we have covered the main points.
Good:
std::sort(v.begin(), v.end());
Erase/Remove is a good example. Though this lambda is terrible.
auto eraseBegin = std::remove_if(v.begin(), v.end(), (const int n)
if (n%4 == 0)
return true;
else
return false;
);
Don't use a if statement
to generate a true/false result. That value is an inherent part of the expression.
if (n%4 == 0)
return true;
else
return false;
Can be simplified to:
return n%4 == 0;
Now that's a good lambda.
auto eraseBegin = std::remove_if(v.begin(), v.end(),
(const int n) return n%4 == 0;);
v.erase(eraseBegin, v.end());
Good:
eraseBegin = std::remove(v.begin(), v.end(), numberToRemove);
v.erase(eraseBegin, v.end());
Good:
auto maxElementIt = std::max_element(v.begin(), v.end());
auto maxElement = *(maxElementIt);
Good:
std::replace(v.begin(), v.end(), maxElement, -1);
I like this: it's a good simple example of random
usage.
void shuffleVector(std::vector <int> &v)
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
std::cerr << "nnPrinting the shuffled vector.nn";
std::for_each(v.begin(), v.end(), printInt);
That random number generator is very expensive to create. And once you have it up and running, why recreate it each time? So I would make the random number stuff static inside the function:
void shuffleVector(std::vector <int> &v) {
static std::random_device rd;
static std::mt19937 g(rd());
As a side note:
The standard introduced std::begin()
and std::end()
. So you can now use these rather than the member versions. This allows you to generalize the code so it can be used on any container type (including arrays).
using std::begin;
using std::end;
std::for_each(begin(v), end(v), doStuff);
Now you don't need to care about the type of v
. You can even change it to a C-Array and it would still work.
edited Apr 18 at 16:55
answered Apr 17 at 15:44
Martin York
70.8k481244
70.8k481244
I apologize if I'm wrong but beyond being expensive to create doesn't a PRNG need to be a single reusable instance like you suggested in order to work properly?
â bruglesco
Apr 17 at 22:09
@bruglesco The new random allows you to create multiple random number generators and they should work independently (and I hear well). But in my personal opinion: One should be enough for an app.
â Martin York
Apr 17 at 23:06
DoesnâÂÂt non-memberbegin
andend
need to be unqualified to really be universal?std::begin
will work for a primitive array and std collections, but not for custom collections and ranges from 3rd party libraries that are not in thestd
namespace. You need to use ADL, just like withswap
.
â JDà Âugosz
Apr 18 at 6:30
Thanks a lot for reviewing in so much detail. Thanks for the useful comments. I will incorporate the suggested changes. I got to learn a lot. :-)
â Rishi Agrawal
Apr 18 at 7:24
@JDÃ Âugosz I see what you are saying. Do be honest I had not thought about that, but its a good point. You are saying for types that don't have abegin/end
method but do have specializations of thebegin/end
free standing methods. Personally I would hope that if you implement iterator like semantics for your object you also implement thebegin/end
method, but I can see how it is not required.
â Martin York
Apr 18 at 16:54
 |Â
show 1 more comment
I apologize if I'm wrong but beyond being expensive to create doesn't a PRNG need to be a single reusable instance like you suggested in order to work properly?
â bruglesco
Apr 17 at 22:09
@bruglesco The new random allows you to create multiple random number generators and they should work independently (and I hear well). But in my personal opinion: One should be enough for an app.
â Martin York
Apr 17 at 23:06
DoesnâÂÂt non-memberbegin
andend
need to be unqualified to really be universal?std::begin
will work for a primitive array and std collections, but not for custom collections and ranges from 3rd party libraries that are not in thestd
namespace. You need to use ADL, just like withswap
.
â JDà Âugosz
Apr 18 at 6:30
Thanks a lot for reviewing in so much detail. Thanks for the useful comments. I will incorporate the suggested changes. I got to learn a lot. :-)
â Rishi Agrawal
Apr 18 at 7:24
@JDÃ Âugosz I see what you are saying. Do be honest I had not thought about that, but its a good point. You are saying for types that don't have abegin/end
method but do have specializations of thebegin/end
free standing methods. Personally I would hope that if you implement iterator like semantics for your object you also implement thebegin/end
method, but I can see how it is not required.
â Martin York
Apr 18 at 16:54
I apologize if I'm wrong but beyond being expensive to create doesn't a PRNG need to be a single reusable instance like you suggested in order to work properly?
â bruglesco
Apr 17 at 22:09
I apologize if I'm wrong but beyond being expensive to create doesn't a PRNG need to be a single reusable instance like you suggested in order to work properly?
â bruglesco
Apr 17 at 22:09
@bruglesco The new random allows you to create multiple random number generators and they should work independently (and I hear well). But in my personal opinion: One should be enough for an app.
â Martin York
Apr 17 at 23:06
@bruglesco The new random allows you to create multiple random number generators and they should work independently (and I hear well). But in my personal opinion: One should be enough for an app.
â Martin York
Apr 17 at 23:06
DoesnâÂÂt non-member
begin
and end
need to be unqualified to really be universal? std::begin
will work for a primitive array and std collections, but not for custom collections and ranges from 3rd party libraries that are not in the std
namespace. You need to use ADL, just like with swap
.â JDà Âugosz
Apr 18 at 6:30
DoesnâÂÂt non-member
begin
and end
need to be unqualified to really be universal? std::begin
will work for a primitive array and std collections, but not for custom collections and ranges from 3rd party libraries that are not in the std
namespace. You need to use ADL, just like with swap
.â JDà Âugosz
Apr 18 at 6:30
Thanks a lot for reviewing in so much detail. Thanks for the useful comments. I will incorporate the suggested changes. I got to learn a lot. :-)
â Rishi Agrawal
Apr 18 at 7:24
Thanks a lot for reviewing in so much detail. Thanks for the useful comments. I will incorporate the suggested changes. I got to learn a lot. :-)
â Rishi Agrawal
Apr 18 at 7:24
@JDÃ Âugosz I see what you are saying. Do be honest I had not thought about that, but its a good point. You are saying for types that don't have a
begin/end
method but do have specializations of the begin/end
free standing methods. Personally I would hope that if you implement iterator like semantics for your object you also implement the begin/end
method, but I can see how it is not required.â Martin York
Apr 18 at 16:54
@JDÃ Âugosz I see what you are saying. Do be honest I had not thought about that, but its a good point. You are saying for types that don't have a
begin/end
method but do have specializations of the begin/end
free standing methods. Personally I would hope that if you implement iterator like semantics for your object you also implement the begin/end
method, but I can see how it is not required.â Martin York
Apr 18 at 16:54
 |Â
show 1 more comment
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f192284%2fexamples-of-lambda-functions-stdfor-each-max-element-remove-if-etc%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
2
Which version of C++ are you targeting?
â nwp
Apr 17 at 12:48
You use
std:for_each
way too much.for (auto& elem: vec) ...
is better unless: 1)for_each
's last argument is an existing function (likestd::for_each(v.begin(), v.end(), printInt);
) or 2) you want to iterate over n elements :std::for_each(v.begin(), v.begin()+3, (auto i) std::cout << i*i; );
â papagaga
Apr 17 at 13:49
A blog on
<algorithm>
isn't a bad idea, but you must aim for something more consistent than these examples, e.g: which king of "raw loops" you can replace with algorithms, which algorithm you should choose, etc.â papagaga
Apr 17 at 13:53
I notice the copyright notice in your code. Which is fine. But I should also note that by posting on this site you are granting a license for the code to be used (see the bottom of the page)
contributions licensed under cc by-sa 3.0
Link: cc by-sa 3.0â Martin York
Apr 17 at 15:10
Sure you can write an article about these. But you are missing the more important algorithms.
std::find()
andstd::transform()
. Thestd::for_each()
has been made a bit redundant withrange based for
. But I think you would be missing the point by just talking about these. Its the combination of algorithm with iterator that makes them interesting. Look at some of the interesting iterators (not just the container iterators)std::istream_iterator
andstd::ostream_iterator
â Martin York
Apr 17 at 15:15