Parent directory Makefile c2cpp_util.h functor.cpp rand1.cpp rand2.cpp
Download
CC = g++ CXX = g++ CFLAGS = -Wall CXXFLAGS = -Wall -std=c++17 executables = functor rand1 rand2 .PHONY: default default: $(executables) .PHONY: clean clean: rm -f a.out core *.o $(executables) .PHONY: all all: clean default
#include <cxxabi.h> #include <typeinfo> #include <cassert> #include <cstdlib> #ifdef __GNUC__ // use abi::__cxa_demangle to demangle type name in g++ & clang++ #define PRINT_TYPE(os, x) do { \ int status; \ char *s = abi::__cxa_demangle(typeid(x).name(), 0, 0, &status); \ assert(status == 0); \ os << s << '\n'; \ std::free(s); \ } while (0) #else // MSVC returns human-readable type name, according to cppreference.com #define PRINT_TYPE(os, x) do { \ os << typeid(x).name() << '\n'; \ } while (0) #endif
#include <array> #include <vector> #include <deque> #include <list> #include <forward_list> #include <iostream> #include <iterator> #include <algorithm> #include <functional> using namespace std; // Pretty much the same as std::for_each template <typename I, typename F> void For_Each(I b, I e, F f) { while (b != e) { f(*b); ++b; } } void print_int(int x) { cout << x << " "; } struct Printer_of_int { void operator()(int x) const { cout << x << ' '; } }; // From: https://en.cppreference.com/w/cpp/language/member_template struct Printer { std::ostream& os; Printer(std::ostream& os) : os(os) {} // template member function template<typename T> void operator()(const T& obj) { os << obj << ' '; } }; int main() { vector<int> v1 { 100, 101, 102, 103, 104 }; vector<int> v2; copy(v1.begin(), v1.end(), back_inserter(v2)); For_Each(v2.begin(), v2.end(), &print_int); cout << '\n'; } /* Lecture outline: 1. Function objects (aka functors) - operator() - template member function code: For_Each(v2.begin(), v2.end(), Printer_of_int{}); cout << '\n'; For_Each(v2.begin(), v2.end(), Printer{cout}); cout << '\n'; 2. STL function objects - Stateless unary & binary functions - Binding argumnets with bind() - std::placeholders::_1 represents the future argument that will be passed to the functor generated by bind() - Composing functions with bind() code: For_Each(v2.begin(), v2.end(), negate<int>()); transform(v1.begin(), v1.end(), back_inserter(v2), negate<int>()); transform(v1.begin(), v1.end(), back_inserter(v2), bind(plus<int>(), placeholders::_1, 300)); transform(v1.begin(), v1.end(), back_inserter(v2), bind(plus<int>(), bind(negate<int>(), placeholders::_1), 300)); 3. Lambda - Lambda expression - Capturing local variables - Type of lambda code: transform(v1.begin(), v1.end(), back_inserter(v2), [] (int x) { return (-x + 300) * 10; }); double a = 2.0, b = 100; auto lambda = [&a, b] (int x) { return a * x + b; }; a = 4.0, b = 1'000'000; transform(v1.begin(), v1.end(), back_inserter(v2), lambda); */
#include <cstdlib> #include <cmath> #include <iostream> #include <iomanip> #include <string> #include <map> #include <random> #include <functional> using namespace std; int main() { // Random number generator using C functions srandom(time(nullptr)); // current time as seed auto engine = &random; // random() in the C library as engine auto distro = [] (auto some_engine) { // get an unsigned random integer from engine, // and "distribute" it in [-10,10] return some_engine() % 21 - 10; }; /* // Random number generator in C++ random_device rd; random_device::result_type seed; seed = (rd.entropy() > 0) ? rd() : time(nullptr); default_random_engine engine { seed }; uniform_int_distribution<> distro { -10, 10 }; */ map<int,int> m; for (int i = 0; i < 1'000'000; ++i) { int x = distro(engine); ++m[x]; } for (const auto& e : m) { cout << setw(4) << e.first << '|' << e.second << '\n'; } }
#include <cstdlib> #include <cmath> #include <iostream> #include <iomanip> #include <string> #include <map> #include <random> #include <functional> #include "c2cpp_util.h" using namespace std; int main() { random_device rd; random_device::result_type seed; seed = (rd.entropy() > 0) ? rd() : time(nullptr); //default_random_engine engine { seed }; //uniform_int_distribution<> distro { -10, 10 }; mt19937 engine { seed }; normal_distribution<> distro { 0.0, 3.5 }; map<int,int> m; int maximum = 0; for (int i = 0; i < 1'000'000; ++i) { int x = lround( distro(engine) ); int occurence = ++m[x]; maximum = max(maximum, occurence); } int bar_scale = maximum / 50; for (const auto& e : m) { cout << setw(4) << e.first << '|' << setw(7) << e.second << '|' << string(e.second / bar_scale, '*') << '\n'; } } /* Lecture outline: 1. Generating normal-distributed random numbers - normal_distribution<> distro { 0.0, 3.5 }; 2. Mersenne Twister engine - mt19937 engine { seed }; 3. Danger of narrowing conversion - subtle bug without lround() int x { distro(engine) }; // compiler warning int x = distro(engine); // no warning, but subtle bug! 4. Stateful functor - binding engine to distro: //int x = lround( distro(engine) ); auto generator = bind(distro, engine); int x = lround( generator() ); - why the same number million times? - capturing distro and engine in a lambda auto generator = bind(distro, engine); //bind(distro, ref(engine)); //[distro, engine] () { return distro(engine); }; //[distro, engine] () mutable { return distro(engine); }; //[=] () mutable { return distro(engine); }; //[&] () { return distro(engine); }; int x = lround( generator() ); - better yet, construct generator outside the loop // The generator object should be constructed outside the loop. auto generator = bind(distro, engine); for (int i = 0; i < 1'000'000; ++i) { 5. *Very* stateful functor - why was it so slow when engine was being copied in the loop? cout << '\n' << typeid(engine).name() << "\n\n"; PRINT_TYPE(cout, engine); cout << "\nsizeof(engine): " << sizeof(engine) << "\n\n"; */