- Higher-Order Functions
- Lambda Expressions
- Pair
a function that taking and/or returning a function
- Accept other functions as arguments (i.e., it takes functions as parameters).
- Return a function as its result (i.e., it produces functions as output).
- Store functions in data structures (e.g., arrays, objects, or lists).
return_type (*function_pointer_name)(argument_types)
#include <iostream>
int add(int x, int y) {
return x + y;
}
int operation(int x, int y, int (*func)(int, int)) {
return func(x, y);
}
int main() {
int a = 5, b = 3;
std::cout << "Add: " << operation(a, b, add) << "\n";
return 0;
}
int atexit(void (*function)(void));
: register a function to be called at normal process termination.
#include <stdlib.h>
#include <iostream>
void bye(void){
std::cout << "That works!\n";
}
int main() {
atexit(bye);
std::cout << "Hello World!\n";
return 0;
}
std::function
: a general-purpose polymorphic function wrapper
introduced in c++11
to replace function pointers.
template<class R, class...Args>
class function<R(Args...)>;
-
int foo(int)
$\rightarrow$ std::function<int(int)>
-
int add(int, int)
$\rightarrow$ std::function<int(int, int)>
#include <iostream>
#include <functional>
int multiply(int x, int y) {
return x * y;
}
int operation(int x, int y, std::function<int(int, int)> func) {
return func(x, y);
}
int main() {
int a = 5, b = 3;
std::function<int(int, int)> mul_f = multiply;
std::cout << "Multiply: " << operation(a, b, mul_f) << "\n";
return 0;
}
int multiply(int x, int y) {
return x * y;
}
std::function<int(int, int)> get_mult() {
return multiply;
}
int main() {
int a = 5, b = 3;
std::function<int(int, int)> mul_f = get_mult();
std::cout << "Multiply: " << operation(a, b, mul_f) << "\n";
return 0;
}
anonymous, inline functions
#include <algorithm>
#include <cmath>
void abssort(float* x, unsigned n) {
std::sort(x, x + n,
// Lambda expression begins
[](float a, float b) {
return (std::abs(a) < std::abs(b));
} // end of lambda expression
);
}
This illustration shows the parts of lambda syntax:
- capture clause (Also known as the lambda-introducer in the C++ specification.)
- parameter list Optional. (Also known as the lambda declarator)
- mutable specification Optional.
- exception-specification Optional.
- trailing-return-type Optional.
- function body.
common forms
[ captures ] ( params ) specs requires (optional) {
function body
}
// if no parameter
[ captures ] {
function body
}
[ ]
: capture nothing in scope[&]
: capture by reference[=]
: capture by value
int x = 5;
int y;
// Capture nothing
auto f0 = [](int y) {
return y;
};
// Capture by value
auto f1 = [=](int y) {
return x + y;
};
// Capture by reference
auto f2 = [&x,&y](int y) {
x++;
return x + y;
};
int y = f2(3);
std::cout << "x: " << x << "\n";
std::cout << "y: " << y << "\n";
auto f = [=]() {
x++;
return x;
};
In C++14, you can introduce and initialize new variables in the capture clause, without the need to have those variables exist in the lambda function's enclosing scope.
std::function<int()> sum(std::vector<int> xs) {
// LAMBDA BEGIN
auto f = [ys = std::move(xs)] {
int sum = 0;
for (int y : ys) {
sum += y;
}
return sum;
};
//LAMBDA ENDS
std::cout << "captured xs len: " << xs.size() << "\n";
return f;
}
int main() {
std::vector<int> xs({1, 2, 3, 4, 5});
auto f = sum(xs);
std::cout << "Sum: " << f() << "\n";
std::cout << "xs len: " << xs.size() << "\n";
return 0;
}
template <typename T> struct Sorter {
std::function<bool(T, T)> cmp;
Sorter(std::function<bool(T, T)> cmp) : cmp(cmp) {}
void sort(std::vector<T> &v) {
std::sort(v.begin(), v.end(), cmp);
}
};
int main() {
std::vector<int> xs{1, 3, 2, 7, 5, 10};
Sorter<int> sorter([](int x, int y) { return x < y; });
sorter.sort(xs);
for (int x : xs) {
std::cout << x << "\n";
}
return 0;
}
two heterogeneous objects as a single unit
a tuple with only 2 elements
Let
template<class _T1, class _T2>
struct pair {
_T1 first; // first is a copy of the first object
_T2 second; // second is a copy of the second object
pair() : first(), second() { }
pair(const _T1& __a, const _T2& __b) : first(__a), second(__b) { }
inline pair<_T1, _T2> make_pair(_T1 __x, _T2 __y){
return pair<_T1, _T2>(__x, __y);
}
}
template <typename T>
bool cmp_pair(std::pair<int, T> a, std::pair<int, T> b) {
return a.first < b.first;
}
int main() {
std::pair<int, std::string> p1(1, "hello");
std::pair<int, std::string> p2(2, "world");
std::cout << cmp_pair(p1, p2) << std::endl;
return 0;
}