3. Лямбда-выражения, функторы и связыватели
Описание файла
PDF-файл из архива "3. Лямбда-выражения, функторы и связыватели", который расположен в категории "". Всё это находится в предмете "проектирование больших систем с++" из 11 семестр (3 семестр магистратуры), которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Просмотр PDF-файла онлайн
Текст из PDF
Проектирование больших систем наC++Коноводов В. А.кафедра математической кибернетики ВМКЛекция 322.09.2017ЗадачаРеализовать TStaticAssert без использования C++11. Ловимошибки на этапе компиляции:TStaticAssert<1 == 1> assert_one_is_one;Лямбда-выраженияБыстрый способ создать такую структуру с оператором ():struct T {bool operator()(int x){};};Do(T(), ...);Лямбда-выраженияБыстрый способ создать такую структуру с оператором ():struct T {bool operator()(int x){};};Do(T(), ...);I[] — список переменных, которые захватываетлямбда-выражение;I() — входные аргументы функции;I{} — тело функции.Лямбда-выражения[capture][capture][capture][capture](params) mutable exception_attribute -> ret {body}(params) -> ret {body}(params) {body}{body}Пример:std::vector<int> v = {-1, -2, -3, -4, -5, 1, 2, 3, 4 ,5};std::sort(v.begin(), v.end(), [](int l, int r) {return l * l < r * r;});Лямбда-выраженияI[] — без захвата переменныхI[=] — все переменные захватываются по значениюI[&] — все переменные захватываются по ссылкеI[x] — захват x по значениюI[&x] — захват x по ссылкеI[x, &y] — захват x по значению, y по ссылкеI[=, &x, &y] — захват всех переменных по значению, ноx,y – по ссылкеI[&, x] — захват всех переменных по ссылке, кроме xI[this] — для доступа к переменной классаreturnВот так не работает:auto cmp = [&data](int a, int b) {if (a == 12)return -1;return data[a] < data[b];};returnВот так не работает:auto cmp = [&data](int a, int b) {if (a == 12)return -1;return data[a] < data[b];};А вот так всё хорошо:auto cmp = [&data](int a, int b) -> int {if (a == 12)return -1;return data[a] < data[b];};mutableТе элементы, которые захвачены по значению, автоматическистановятся константами внутри лямбды.auto cmp = [&d, d1](int a, int b) mutable -> int {d[0] = d1[0] = 0;if (a == 12)return -1;return d[a] < d[b];};УпражнениеОтсортировать массив, не испортив его — вывестиперестановку, сохранив исходные данные.const int a[] = {3, 5, 2, 8, 15, 12, -1, 3, 4, 7};size_t n = sizeof(a) / sizeof(a[0]);std::vector<size_t> idx(n);for (int i = 0; i < n; ++i) {idx[i] = i;}// ...
?for (const auto &i : idx) {std::cout << a[i] << " ";}std::cout << std::endl;}// cОпасности захвата по умолчаниюusing T = std::vector<std::function<bool(int)>>;void AddFunc(T& funcs) {static int x = 2;funcs.emplace_back([=](int v) { return v % x == 0;});++x;}int main() {T funcs;AddFunc(funcs);AddFunc(funcs);funcs[0](5);funcs[1](5);}Захватывать явно — заметнее ошибки.Захватывать указатель тоже может быть опасно.std::functionstruct Foo {void print(int i) const { std::cout << i << std::endl; }};void print_num(int i) {std::cout << i << std::endl;}int main() {std::function<void(int)> f_display = print_num;f_display(1);std::function<void()> f_display_2 = []() { print_num(2); };f_display_2();std::function<void(const Foo&, int)> f_add_display =&Foo::print;f_add_display(Foo(), 1);}Отступление: указатели на методы внутриклассаclass C {private:int a, b;public:C(int a, int b) : a(a), b(b) {};void f() const { ...
}void g() const { ... }};Хотим сделать указатель на функцию f из класса,void (*ptr) ();ptr = &C::f;//// так нельзяОтступление: указатели на методы внутриклассаclass C {private:int a, b;public:C(int a, int b) : a(a), b(b) {};void f() const { ... }void g() const { ... }};Хотим сделать указатель на функцию f из класса,void (*ptr) ();ptr = &C::f;//// так нельзяvoid (C::*ptr)() const;ptr = &C::f;// okФункторы в <functional>greaterlessgreater_equalless_equalequal_tonot_equal_toplusminusmultiplydividenegate moduluslogical_andlogical_orlogical_notФункторы в <functional>greaterlessgreater_equalless_equalequal_tonot_equal_toplusminusmultiplydividenegate moduluslogical_andlogical_orlogical_notsort(a, a + 5, std::greater<int>());transform(a, a + 5, b, ostream_iterator<int> (cout, " "),plus<int>());Связыватели в C++98remove_copy_if (a,a + 5,ostream_iterator<int> (cout, " "),bind2nd(less<int>(), 3));Связыватели в C++98Но вот так не работает:class MyCmp {public:bool operator()(int a, int b) const {return a > b;}};remove_copy_if (a.begin(),a.end(),b.begin(),std::bind2nd(MyCmp(), 3));Связыватели в C++98А так ok:class MyCmp : public std::binary_function<int, int, bool>{public:bool operator()(int a, int b) const {return a > b;}};remove_copy_if (a.begin(),a.end(),b.begin(),std::bind2nd(MyCmp(), 3));std::mem_fun_ref и std::mem_funclass C {int a;public:C(int a) : a(a) {}void f() const {std::cout << a << std::endl;}};int main() {C c [] = {C(1), C(2), C(3), C(4)};C* cptr [] = {c, c + 1, c + 2, c + 3};std::for_each(c, c + 4, std::mem_fun_ref(&C::f));std::mem_fun_ref и std::mem_funclass C {int a;public:C(int a) : a(a) {}void f() const {std::cout << a << std::endl;}};int main() {C c [] = {C(1), C(2), C(3), C(4)};C* cptr [] = {c, c + 1, c + 2, c + 3};std::for_each(c, c + 4, std::mem_fun_ref(&C::f));std::for_each(cptr, cptr + 4, std::mem_fun(&C::f));std::mem_fun_ref и std::mem_funclass C {int a;public:C(int a) : a(a) {}void f() const {std::cout << a << std::endl;}};int main() {C c [] = {C(1), C(2), C(3), C(4)};C* cptr [] = {c, c + 1, c + 2, c + 3};std::for_each(c, c + 4, std::mem_fun_ref(&C::f));std::for_each(cptr, cptr + 4, std::mem_fun(&C::f));std::for_each(c, c + 4,std::function<void(const C&)>(&C::f));std::mem_fun_ref и std::mem_funclass C {int a;public:C(int a) : a(a) {}void f() const {std::cout << a << std::endl;}};int main() {C c [] = {C(1), C(2), C(3), C(4)};C* cptr [] = {c, c + 1, c + 2, c + 3};std::for_each(c, c + 4, std::mem_fun_ref(&C::f));std::for_each(cptr, cptr + 4, std::mem_fun(&C::f));std::for_each(c, c + 4,std::function<void(const C&)>(&C::f));std::for_each(cptr, cptr + 4,std::function<void(const C*)>(&C::f));}mem_fn в C++11В С++11 mem_fun и mem_fun_ref заменены на mem_fn.
Онvariadic — может работать с произвольным числом аргументов.C c(1);auto g = std::mem_fn(&C::f);// the same:auto g2 = [] (C& c, int x) { return c.f(x); } ;g(c, 10);C++11: std::bindint f(int a, int b) {return a - b;}int main() {auto g = std::bind(f, 3, std::placeholders::_2);std::cout << g(1, 4) << std::endl;return 0;}C++11: std::bindint f(int a, int b) {return a - b;}int main() {auto g = std::bind(f, 3, std::placeholders::_2);std::cout << g(1, 4) << std::endl;return 0;}-1C++11: std::bindint f(int a, int b) {return a - b;}int main() {auto g = std::bind(f, 3, std::placeholders::_2);std::cout << g(1, 4) << std::endl;return 0;}-1std::bind(f, _2, _1, 2, 3, 4) (x, y);// f(y, x, 2, 3, 4)C++11: std::bindint f(int a, int b) {return a - b;}int g(int x) {return x * x;}int main() {auto f2 = std::bind(f,std::bind(g,std::placeholders::_2),std::placeholders::_1);std::cout << f2(3, 7) << std::endl;}C++11: std::bindЕсли нужно привязаться к методу класса:class T {int x;public:T(int x) : x(x) {}void print(int a, int b) {std::cout << a << " " << b << " " << x << std::endl;}};int main() {T t(10);auto f3 = std::bind(&T::print, t, 1, std::placeholders::_1);f3(17);}УпражнениеНаписать функцию-связыватель Compose, которая строитфунктор-суперпозицию.Пример: перевести в массив double одним вызовомstd::transpose массив std::string, в котором записаныдробные числа.string s[] = {"1.2", "2.343", "3.2"};vector<double> d(3);transform(s,s + 3,d.begin(),compose(std::ptr_fun(atof),std::mem_fun_ref(&string::c_str)));Проблемаclass C {public:void f(int x)std::cout}void f(doublestd::cout}};{<< "f(int) " << x << std::endl;x) {<< "f(double) " << x << std::endl;int main() {C x;x.f(1); x.f(1.1);auto g = std::mem_fn(&C::f);}.