You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#include<iostream>usingnamespacestd;intmain()
{
auto f = [](auto a, auto b)
{
return a + b;
};
cout << f(1, 2) << "\n";
cout << f("Hello "s, "world") << "\n";
}
You can write generic lambdas using auto for its arguments.
This isn't allowed for regular functions.
<algorithm>
The standard library provides a long list of algorithms in <algorithm>. Most are function templates that take iterator arguments.
#include<iostream>
#include<algorithm>
#include<random>
#include<vector>usingnamespacestd;intmain()
{
vector<int> v (100);
iota(v.begin(), v.end(), 0);
for (auto & i : v)
cout << i << "";
cout << "\n\n";
random_device rd;
default_random_engine g(rd());
shuffle(v.begin(), v.end(), g);
for (auto & i : v)
cout << i << "";
cout << "\n\n";
replace_if(v.begin(), v.end(), [](auto & i)
{
return i > 50;
}, 50);
for (auto & i : v)
cout << i << "";
cout << "\n\n";
sort(v.begin(), v.end());
for (auto & i : v)
cout << i << "";
cout << "\n\n";
}
iota fills a range with an incrementing sequence.
The standard library also provide classes (in <random>) that generate random and pseudorandom numbers in much more sophisticated ways than C rand and srand. See the documentation for more details.
shuffle reorders the range such that any permutation has equal probability to be chosen. It requires a source of random numbers.
replace and replace_if replace some elements of a range.
sort sorts a range defined by random access iterators.
Other containers like list have a member sort function, since the implementation has to differ.
Modifying containers
None of the algorithms add or remove elements of a container, they only operate on ranges defined by iterators, so they are unable to affect the size of the actual container.
#include<iostream>
#include<algorithm>
#include<vector>usingnamespacestd;intmain()
{
vector<int> v {1, 2, 3};
auto end = remove(v.begin(), v.end(), 1);
for_each(v.begin(), end, [](auto & i)
{
cout << i << "";
});
cout << "\n";
for (auto & i : v)
cout << i << "";
}
e.g. remove shifts the elements in the range to remove some elements, and returns a new end of range iterator. The underlying container's size is unchanged.
#include<iostream>
#include<algorithm>
#include<vector>usingnamespacestd;intmain()
{
vector<int> v {1, 2, 3};
auto end = remove(v.begin(), v.end(), 1);
v.erase(end, v.end());
for (auto & i : v)
cout << i << "";
}
One option to modify a container is by directly referring to it.
e.g. after calling remove call erase on the container with the iterator returned by remove.
#include<iostream>
#include<algorithm>
#include<vector>
#include<iterator>usingnamespacestd;intmain()
{
vector<int> v1 {1, 2, 3};
vector<int> v2;
copy(v1.begin(), v1.end(), back_inserter(v2));
for (auto & i : v2)
cout << i << "";
}
You can also use something that knows about the container to modify it.
e.g. back_inserter, inserter, and front_inserter (in <iterator>) create special iterators that call push_back, insert, and push_front respectively, so the container will grow when things are written to the iterator.
#include<execution>
#include<algorithm>
#include<iostream>
#include<vector>usingnamespacestd;intmain()
{
vector<int> v;
for (int i = 0; i < 1e2; ++i)
{
v.emplace_back(i);
}
auto f = [](auto & i)
{
cerr << i << "";
};
for_each(v.begin(), v.end(), f);
cin.get();
cerr << "\n";
for_each(execution::par, v.begin(), v.end(), f);
cin.get();
cerr << "\n";
for_each(execution::par_unseq, v.begin(), v.end(), f);
// parallelization can help a lot for sort (increase the vector size)// sort(execution::par, v.begin(), v.end());
}
Most functions also accept an execution policy (as the first argument), which allows for parallelization.
If an execution policy is not specified, execution::seq (sequential) is the default.
execution::par
Permits the algorithm to be parallelized.
execution::par_unseq
Permits the algorithm to be parallelized and vectorized (unsequenced execution on a single thread, using SIMD instructions.
Can break some synchronization methods (more on this next lecture).
These execution policies are guidelines to the compiler. It is not guaranteed that using them will actually generate parallel code.
Execution policies are badly supported by g++. It was implemented in g++ 9.1 (earlier this year) using the Intel TBB library (-ltbb flag at the end of the command to link the library).
This code is unlikely to run on your machine without installing anything new.
Use the instructions at this link to install the dependencies.
Functional programming in C++
C++ is a multi-paradigm language.
We've seen OOP, generic programming, procedural programming so far. Functional programming is also possible.
So far we have used templates to take functors/lambdas/function pointers parameters.
In fact, in the case of lambdas, they have some unspecified unique type, so you cannot write its type without auto.
function is a function object that holds any callable function.
Needed (actually, there are some workarounds without using function) for recursive lambdas since auto needs to know its own type, but its own type (from auto) depends on itself.
We need to capture by reference since capturing by value gets an uninitialized function.
Note that you can't return this lambda since depends on a local variable (itself).
#include<iostream>
#include<vector>
#include<functional>usingnamespacestd;classfunctor
{
public:booloperator()(int i)
{
return i == 0;
}
};
boolf2(int i)
{
return i == 1;
}
intmain()
{
functor f1;
vector<function<bool(int)>> funcs {f1, f2, [](int i){ return i == 2; }};
for (auto & f : funcs)
cout << f(1) << "";
}
Also useful if you have a heterogeneous collection of functions to call with the same signature, but not necessarily the same type.
You should prefer templates to function if possible though, since function can have some runtime overhead. Conceptually, templates are also a "safer" option since they involve static (compile-time) checks.