Created
July 6, 2018 17:12
-
-
Save caiorss/c57ffb464a8372cae3ffde5541250364 to your computer and use it in GitHub Desktop.
C++11 std::bind usage examples with higher order functions std::functions and function-objects C++'s functor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ clang++ bindTest.cpp -std=c++11 -Wall -Wextra -g -o out.bin && ./out.bin | |
======== Test 1 ======== | |
bindTest.cpp:58: ; sum10(2.0) = 12 | |
bindTest.cpp:59: ; sum10(4.5) = 14.5 | |
bindTest.cpp:60: ; sum10(25.0) = 35 | |
======== Test 2 ======== | |
bindTest.cpp:66: ; vectorLenAsFunctionOfX(4.0) = 27.2213 | |
bindTest.cpp:67: ; std::bind(vectorLength, _1, 10.0, 25.0)(4.0) = 27.2213 | |
bindTest.cpp:68: ; vectorLenAsFunctionOfX(10.0) = 28.7228 | |
bindTest.cpp:69: ; std::bind(vectorLength, _1, 10.0, 25.0)(10.0) = 28.7228 | |
Tabulating - vectorLenAsFunctionOfX | |
1.000 26.944 | |
2.000 27.000 | |
3.000 27.092 | |
4.000 27.221 | |
5.000 27.386 | |
======== Test 3 ======== | |
bindTest.cpp:77: ; vectorLenAsFunctionOfY(14.0) = 30.348 | |
bindTest.cpp:78: ; vectorLenAsFunctionOfY(20.0) = 33.541 | |
Tabulating - vectorLenAsFunctionOfY | |
1.000 26.944 | |
2.000 27.000 | |
3.000 27.092 | |
4.000 27.221 | |
5.000 27.386 | |
======== Test 4 ======== | |
bindTest.cpp:92: ; vectorLenAsFunctionOfYZ(3.0, 6.0) = 12.0416 | |
bindTest.cpp:93: ; vectorLenAsFunctionOfYZ(15.0, 26.0) = 31.6386 | |
======== Test 5 ======== | |
bindTest.cpp:97: ; fobj(4.0) = 16 | |
bindTest.cpp:98: ; fobj(5.0) = 25 | |
bindTest.cpp:99: ; fobj(10.0) = 100 | |
bindTest.cpp:101: ; fobj(4.0, 10.0, 5.0) = 104.357 | |
bindTest.cpp:102: ; fobj(6.0, 8.0, 9.0) = 100.643 | |
Running: tabulate(0.0, 5.0, 1.0, fobj) | |
0.000 0.000 | |
1.000 1.000 | |
2.000 4.000 | |
3.000 9.000 | |
4.000 16.000 | |
5.000 25.000 | |
Turning class member function into lambda function | |
Note: it is not possible (0.0, 5.0, 1.0, fobj.method1) | |
bindTest.cpp:111: ; fobj.method1(10.0) = 60.8 | |
bindTest.cpp:112: ; method1LambdaA(10.0) = 60.8 | |
bindTest.cpp:113: ; fobj.method1(20.0) = 120.4 | |
bindTest.cpp:114: ; method1LambdaA(20.0) = 120.4 | |
bindTest.cpp:115: ; fobj.method1(30.0) = 180.267 | |
bindTest.cpp:116: ; method1LambdaA(30.0) = 180.267 | |
Tabulating method1LambdaA | |
0.000 inf | |
1.000 14.000 | |
2.000 16.000 | |
3.000 20.667 | |
4.000 26.000 | |
5.000 31.600 | |
Tabulating method1LambdaA using direct lambda | |
0.000 inf | |
1.000 14.000 | |
2.000 16.000 | |
3.000 20.667 | |
4.000 26.000 | |
5.000 31.600 | |
======== Test 6 ======== | |
bindTest.cpp:129: ; method2LambdaAsFnOfA(5.0) = 41.6667 | |
bindTest.cpp:130: ; method2LambdaAsFnOfA(6.0) = 45 | |
bindTest.cpp:131: ; method2LambdaAsFnOfA(10.0) = 58.3333 | |
bindTest.cpp:136: ; fobj.method2(3.0, 10.0, 4.0) = 7 | |
bindTest.cpp:137: ; method2LambdaAsFnOfAC(3.0, 4.0) = 7 | |
bindTest.cpp:138: ; fobj.method2(15.0, 10.0, 14.0) = 52.5 | |
bindTest.cpp:139: ; method2LambdaAsFnOfAC(15.0, 14.0) = 52.5 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> // cout, cin, endl | |
#include <functional> // Import std::function, bind, placeholders, _1, _2, _3 ... | |
#include <iomanip> // | |
#include <cmath> // sin, cos, tan, sqrt ... | |
#include <vector> // std::vector<X> | |
/* Debug macro to print expressions - disp(x * 10 + 5) will print | |
* on cerr (standard error output stream) the line: | |
* "line = 105 file = test.cpp ; x * 10 + 5 = 25" | |
*/ | |
#define disp(expr) std::cerr << __FILE__ << ":" << __LINE__ << ":" \ | |
<< " ; " << #expr << " = " << (expr) << std::endl | |
#define dbgloc(msg) std::cerr << __FILE__ << ":" << __LINE__ << ":" << msg | |
#define dbgline __FILE__ << ":" << __LINE__ << ":" << | |
#define dbgtrace(msg) std::cout << __FILE__ << ":" << __LINE__ << ": TRACING " << msg << "\n"; | |
// type Mfun = double => double | |
using Mfun = std::function<double (double)>; | |
using NumVector = std::vector<double>; | |
// ========== Prototypes =============// | |
NumVector mapVector(NumVector& xs, Mfun fn); | |
NumVector makeVector(int size, std::function<double (int i)>); | |
void tabulate(double start, double stop, double step, Mfun fn); | |
double vectorLength(double x, double y, double z); | |
double sum(double x, double y); | |
// Function object | |
struct FunctionObject{ | |
double x; | |
double y; | |
FunctionObject(double x, double y): x(x), y(y) {}; | |
double operator ()(double a){ | |
return a * a; | |
} | |
double operator ()(double a, double b, double c){ | |
return a * x + b * y + c / (x + y); | |
} | |
double method1(double a){ | |
return this->x * a + this->y / a; | |
} | |
double method2(double a, double b, double c){ | |
return c * (a / x + b / y); | |
} | |
}; | |
int main(){ | |
using std::cout; | |
using std::endl; | |
using namespace std::placeholders; // Import placeholders, _1, _2, _3 ... | |
cout << "======== Test 1 ========" << endl; | |
// Verbose signature | |
std::function<double (double)> sum10 = std::bind(sum, 10, _1); | |
disp(sum10(2.0)); | |
disp(sum10(4.5)); | |
disp(sum10(25.0)); | |
cout << "======== Test 2 ========" << endl; | |
// Fix y = 10.0 and z = 25.0 - set x as variable | |
Mfun vectorLenAsFunctionOfX = std::bind(vectorLength, _1, 10.0, 25.0); | |
disp(vectorLenAsFunctionOfX(4.0)); | |
disp(std::bind(vectorLength, _1, 10.0, 25.0)(4.0)); | |
disp(vectorLenAsFunctionOfX(10.0)); | |
disp(std::bind(vectorLength, _1, 10.0, 25.0)(10.0)); | |
cout << "Tabulating - vectorLenAsFunctionOfX" << endl; | |
tabulate(1.0, 5.0, 1.0, vectorLenAsFunctionOfX); | |
cout << "======== Test 3 ========" << endl; | |
// Fix x = 10.0, z = 25.0 - set y as variable | |
auto vectorLenAsFunctionOfY = std::bind(vectorLength, 10.0, _1, 25.0); | |
disp(vectorLenAsFunctionOfY(14.0)); | |
disp(vectorLenAsFunctionOfY(20.0)); | |
cout << "Tabulating - vectorLenAsFunctionOfY" << endl; | |
tabulate(1.0, 5.0, 1.0, vectorLenAsFunctionOfY); | |
cout << "======== Test 4 ========" << endl; | |
// Note: auto could be used here to simplify the singature. | |
// It is the same as writing: | |
// | |
// vectorLenAsFunctionOfYZ = | |
// [&](double y, double z){ return vectorLength(10.0, y, z)}; | |
std::function<double (double, double)> vectorLenAsFunctionOfYZ = | |
std::bind(vectorLength, 10.0, _1, _2); | |
disp(vectorLenAsFunctionOfYZ(3.0, 6.0)); | |
disp(vectorLenAsFunctionOfYZ(15.0, 26.0)); | |
cout << "======== Test 5 ========" << endl; | |
FunctionObject fobj(6.0, 8.0); | |
disp(fobj(4.0)); | |
disp(fobj(5.0)); | |
disp(fobj(10.0)); | |
disp(fobj(4.0, 10.0, 5.0)); | |
disp(fobj(6.0, 8.0, 9.0)); | |
cout << "Running: tabulate(0.0, 5.0, 1.0, fobj)" << endl; | |
tabulate(0.0, 5.0, 1.0, fobj); | |
cout << "Turning class member function into lambda function " << endl; | |
cout << " Note: it is not possible (0.0, 5.0, 1.0, fobj.method1)" << endl; | |
// Equivalent to:: method1LambdaA = [&fobj](double x){ return fobj.method(x); }; | |
Mfun method1LambdaA = std::bind(&FunctionObject::method1, &fobj, _1); | |
disp(fobj.method1(10.0)); | |
disp(method1LambdaA(10.0)); | |
disp(fobj.method1(20.0)); | |
disp(method1LambdaA(20.0)); | |
disp(fobj.method1(30.0)); | |
disp(method1LambdaA(30.0)); | |
cout << "Tabulating method1LambdaA" << endl; | |
tabulate(0.0, 5.0, 1.0, method1LambdaA); | |
cout << "Tabulating method1LambdaA using direct lambda" << endl; | |
tabulate(0.0, 5.0, 1.0, std::bind(&FunctionObject::method1, &fobj, _1)); | |
cout << "======== Test 6 ========" << endl; | |
// set parameters a = <variable>, b = 10.0 , c = 20.0 | |
auto method2LambdaAsFnOfA = | |
std::bind(&FunctionObject::method2, &fobj, _1, 10.0, 20.0); | |
disp(method2LambdaAsFnOfA(5.0)); | |
disp(method2LambdaAsFnOfA(6.0)); | |
disp(method2LambdaAsFnOfA(10.0)); | |
// set parameters a = <var>, b = 25.0> , c = <var> | |
auto method2LambdaAsFnOfAC = | |
std::bind(&FunctionObject::method2, &fobj, _1, 10.0, _2); | |
disp(fobj.method2(3.0, 10.0, 4.0)); | |
disp(method2LambdaAsFnOfAC(3.0, 4.0)); | |
disp(fobj.method2(15.0, 10.0, 14.0)); | |
disp(method2LambdaAsFnOfAC(15.0, 14.0)); | |
} | |
//////////////// Prototypes Implementations /////////////////////////// | |
NumVector mapVector(NumVector& xs, Mfun fn){ | |
NumVector ys(xs.size()); | |
int n = xs.size(); | |
for(int i =0; i < n; i++){ | |
ys[i] = fn(xs[i]); | |
} | |
return ys; | |
} | |
NumVector makeVector(int size, std::function<double (int i)> fn){ | |
NumVector ys(size); | |
for(int i =0; i < size; i++){ | |
ys[i] = fn(i); | |
} | |
return ys; | |
} | |
void tabulate(double start, double stop, double step, Mfun fn){ | |
double x = start; | |
while(x <= stop){ | |
std::cout << std::fixed | |
<< std::setw(10) << std::setprecision(3) << x | |
<< std::setw(10) << std::setprecision(3) << fn(x) | |
<< "\n"; | |
x += step; | |
} | |
} | |
double vectorLength(double x, double y, double z){ | |
return sqrt(x * x + y * y + z * z); | |
} | |
double sum(double x, double y){ | |
return x + y; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment