Скачать презентацию Современный C 5 крутых фишек Алексей Малов i Скачать презентацию Современный C 5 крутых фишек Алексей Малов i

Современный C++, 5 крутых фишек.pptx

  • Количество слайдов: 74

Современный C++ 5 крутых фишек Алексей Малов i. Spring Solutions www. ispringsolutions. com Современный C++ 5 крутых фишек Алексей Малов i. Spring Solutions www. ispringsolutions. com

Содержание • Семантика перемещения • Умные указатели • Optional • Variant • Контейнеры, диапазоны, Содержание • Семантика перемещения • Умные указатели • Optional • Variant • Контейнеры, диапазоны, алгоритмы • Применение функционального программирования

Семантика перемещения Семантика перемещения

Семантика перемещения • Позволяет компилятору заменить дорогостоящую операцию копирования менее дорогими перемещениями • Копирование Семантика перемещения • Позволяет компилятору заменить дорогостоящую операцию копирования менее дорогими перемещениями • Копирование vector, string • Время: O(N) • Память: O(N) – для хранения копии • Может выбросить исключение • Перемещение vector, string • Время: O(1) • Память: O(1) • Как правило, не бросает исключений • Некоторые типы могут только перемещаться • std: : fstream, std: : unique_ptr, std: : future, std: : thread

struct Person { string name; string surname; }; struct Department { string name; vector<Person> struct Person { string name; string surname; }; struct Department { string name; vector employees; }; C++’ 03 Department Read. Department(istream& input) { Department department; Person p; if (getline(input, department. name)) { string line; while (getline(input, line)) { istringstream strm(line); if (strm >> p. name && strm >> p. surname) Копирование сотрудников при department. employees. push_back(p); изменерии размеров контейнера } } Может приводить к копированию return department; всего Department }

Что происходит при копировании H ap p y Happy n ew new y ea Что происходит при копировании H ap p y Happy n ew new y ea r year! vector H ap p y Happy n ew new vector y ea r year!

Что происходит при перемещении H ap p y Happy n ew new y ea Что происходит при перемещении H ap p y Happy n ew new y ea r year! vector

struct Person { string name; string surname; }; struct Department { string name; vector<Person> struct Person { string name; string surname; }; struct Department { string name; vector employees; }; Department Read. Department(istream& input) { Department department; Person p; if (getline(input, department. name)) { string line; while (getline(input, line)) { istringstream strm(line); if (strm >> p. name && strm >> p. surname) department. employees. emplace_back(move(p)); } } return department; } C++’ 14 Элемент конструируется путем перемещения значения из p

Move-only типы • Для них операция копирования не имеет смысла • Полезно иметь возможность Move-only типы • Для них операция копирования не имеет смысла • Полезно иметь возможность перемещения значения от одного объекта • Возврат результата из функции • Передача аргумента в функцию • Пример: • Объекты типа Handle, управляющие некоторыми ресурсами ОС

namespace detail { template <HANDLE INVALID> class Handle { HANDLE m_handle = INVALID; public: namespace detail { template class Handle { HANDLE m_handle = INVALID; public: Handle() = default; explicit Handle(HANDLE handle = INVALID) : m_handle(handle) {} Handle(Handle&& x) : m_handle(x. m_handle) { x. m_handle = INVALID; } Handle(const Handle&) = delete; // no copy construction Handle& operator=(Handle&& x) {// move assignment std: : swap(m_handle, x. m_handle); return *this; } Handle &operator=(const Handle&) = delete; // no copy assignment

 ~Handle() { if (m_handle != INVALID) { Close. Handle(m_handle); } } explicit operator ~Handle() { if (m_handle != INVALID) { Close. Handle(m_handle); } } explicit operator bool() const { return m_handle != INVALID; } operator HANDLE() const { return m_handle; } void Close() { if (!Close. Handle(m_handle)) { m_handle = INVALID; throw std: : runtime_error("Failed to close handle"); } m_handle = INVALID; } }; } // namespace detail using File. Handle = detail: : Handle;

Пример использования File. Handle Safe. Open. File(LPCWSTR file. Name) { File. Handle fh(Create. File. Пример использования File. Handle Safe. Open. File(LPCWSTR file. Name) { File. Handle fh(Create. File. W(file. Name, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); if (!fh) throw runtime_error("Failed to open file"); return fh; } int main() { auto f = Safe. Open. File(L"main. cpp"); DWORD file. Size = Get. File. Size(f, nullptr); if (file. Size != INVALID_FILE_SIZE) cout << "File size: " << file. Size << "n"; }

Умные указатели Умные указатели

unique_ptr • Единолично владеет объектом через его указатель • Move-only • Нулевой оверхед + unique_ptr • Единолично владеет объектом через его указатель • Move-only • Нулевой оверхед + RAII • Совместим с stl-контейнерами • Позволяет управлять массивом объектов в куче • Поддержка пользовательского deleter-а • R. I. P. auto_ptr

Идиома Pimpl (pointer to implementation) • Вместо хранения данных, класс хранит указатель на структуру Идиома Pimpl (pointer to implementation) • Вместо хранения данных, класс хранит указатель на структуру или класс с деталями реализации • Скрывает лишние зависимости из заголовочного файла • Позволяет сократить время компиляции

Пример – идиома Pimpl class Opaque. Obj { Opaque. Obj. h public: Opaque. Obj(int Пример – идиома Pimpl class Opaque. Obj { Opaque. Obj. h public: Opaque. Obj(int data); ~Opaque. Obj(); void Foo(); private: struct Impl; Impl* m_impl; }; #include "Opaque. Obj. h" Opaque. Obj. cpp struct Opaque. Obj: : Impl { Impl(int data) : m_data(data) {} void Foo() { /* do something */ } int m_data = 42; }; Opaque. Obj: : Opaque. Obj(int data) : m_impl(new Impl(data)) {} Opaque. Obj: : ~Opaque. Obj() { delete m_impl; } Проблема – требуется реализовать или запретить конструктор копирования и оператор присваивания void Opaque. Obj: : Foo() { m_impl->Foo(); }

Идиома Pimpl с unique_ptr class Opaque. Obj { Opaque. Obj. h public: Opaque. Obj(int Идиома Pimpl с unique_ptr class Opaque. Obj { Opaque. Obj. h public: Opaque. Obj(int data); ~Opaque. Obj(); void Foo(); private: struct Impl; unique_ptr m_impl; }; #include "Opaque. Obj. h" Opaque. Obj. cpp struct Opaque. Obj: : Impl { Impl(int data) : m_data(data) {} void Foo() { /* do something */ } int m_data = 42; }; Opaque. Obj: : Opaque. Obj(int data) : m_impl(make_unique(data)){} Opaque. Obj: : ~Opaque. Obj() = default; Приятный бонус: Opaque. Obj из коробки стал Move-only типом void Opaque. Obj: : Foo() { m_impl->Foo(); }

Умное управление ресурсами библиотеки языка C typedef struct tag. Data { int value; } Умное управление ресурсами библиотеки языка C typedef struct tag. Data { int value; } Data; Data* Allocate. Data(); void Do. Something. With. Data(Data *data, int x); void Deallocate. Data(Data* data);

int Calculate. X(int value); Код по-прежнему содержит проблему bool Foo() { Data *p = int Calculate. X(int value); Код по-прежнему содержит проблему bool Foo() { Data *p = Allocate. Data(); if (!p) { cout << "Failed to allocated datan"; return false; } if (p->value == 42) { Deallocate. Data(p); return true; } Do. Something. With. Data(p, Calculate. X(p->value)); Deallocate. Data(p); return false; }

int Calculate. X(int value) { if (value < 0) throw std: : invalid_argument( int Calculate. X(int value) { if (value < 0) throw std: : invalid_argument("Invalid argument"); return value + 1; } bool Foo() { Data *p = Allocate. Data(); if (!p) { cout << "Failed to allocated datan"; return false; } if (p->value == 42) { Deallocate. Data(p); return true; } Если Calculate. X выбросит исключение, Deallocate. Data вызван не будет Do. Something. With. Data(p, Calculate. X(p->value)); Deallocate. Data(p); return false; }

Пользовательский deleter struct Data. Deleter { void operator()(Data *data) const noexcept { Deallocate. Data(data); Пользовательский deleter struct Data. Deleter { void operator()(Data *data) const noexcept { Deallocate. Data(data); } }; using Data. Ptr = std: : unique_ptr; Data. Ptr Safe. Allocate. Data() { if (Data. Ptr p{Allocate. Data()}) return p; throw std: : runtime_error("Failed to allocate data"); }

Было bool Foo() { Data *p = Allocate. Data(); if (!p) { cout << Было bool Foo() { Data *p = Allocate. Data(); if (!p) { cout << "Failed to allocated datan"; return false; } if (p->value == 42) { Deallocate. Data(p); return true; } Do. Something. With. Data(p, Calculate. X(p->value)); Deallocate. Data(p); return false; }

Стало bool Foo() { try { auto p = Safe. Allocate. Data(); if (p->value Стало bool Foo() { try { auto p = Safe. Allocate. Data(); if (p->value == 42) return true; Do. Something. With. Data(p. get(), Calculate. X(p->value)); } catch (std: : exception const &e) { cout << e. what() << "n"; } return false; }

shared_ptr • Умный указатель, основанный на подсчете ссылок • Обеспечивает совместное владение объектом • shared_ptr • Умный указатель, основанный на подсчете ссылок • Обеспечивает совместное владение объектом • Возможность управления не только памятью • Накладные расходы • Память для хранения счетчиков • Thread-safe подсчет ссылок shared_ptr Object ptr counter. Ptr shared. Count weak. Count deleter

Master weak_ptr • Слабая ссылка на объект • Не влияет на время жизни • Master weak_ptr • Слабая ссылка на объект • Не влияет на время жизни • Автоматически обнуляется после удаления объекта • Пока объект жив, позволяет получить shared_ptr на него • Решает проблему циклических ссылок и висячих указателей weak_ptr Object ptr counter. Ptr shared. Count weak. Count deleter Slave

enable_shared_from_this • Позволяет объекту, управляемому shared_ptr, безопасно создать экземпляр shared_ptr на самого себя • enable_shared_from_this • Позволяет объекту, управляемому shared_ptr, безопасно создать экземпляр shared_ptr на самого себя • shared_from_this() • weak_from_this () (C++ 17) • Нельзя вызывать shared_from_this() из конструктора и деструктора, а также у объекта, не обернутого в shared_ptr • До C++ 17 грозило UB • В C++17 – исключение bad_weak_ptr • Применимость • Передача shared-ссылки на самого себя • Реализация идиомы weak this • Защита от преждевременного удаления при вызове внешнего кода

using Node. Ptr = shared_ptr<struct Node>; Позволяет получать shared_ptr на себя struct Node : using Node. Ptr = shared_ptr; Позволяет получать shared_ptr на себя struct Node : enable_shared_from_this { void Add. Child(const Node. Ptr& node) { auto self = shared_from_this(); if (node == self || Is. Descendant. Of(node)) throw invalid_argument("Can't add self or ancestor"); if (m_children. emplace(node). second) { if (auto old. Parent = node->Get. Parent()) old. Parent->m_children. erase(node); node->m_parent = self; } } Node. Ptr Get. Parent()const { return m_parent. lock(); } bool Is. Descendant. Of(const Node. Ptr& node)const { auto self = shared_from_this(); for (auto x = node->Get. Parent(); x; x = x->Get. Parent()) if (x == self) return true; return false; } private: Слабая ссылка на родителя нужна для weak_ptr m_parent; устранения циклических связей unordered_set m_children; };

Задача: асинхронная загрузка изображения в GUI-приложении struct Image { /* some image data */ Задача: асинхронная загрузка изображения в GUI-приложении struct Image { /* some image data */ }; using Callback = function image)>; void Load. Image. Async(string_view url, Callback callback); struct Image. View { void Show. Image. At. URL(string_view url) { /* Загрузить изображение асинхронно и вызвать On. Image. Loaded */ } private: void On. Image. Loaded(string_view url, unique_ptr image); }; ? ? ?

Решение, которое (иногда) не работает Почему? using Callback = function<void(string_view url, unique_ptr<Image> image)>; void Решение, которое (иногда) не работает Почему? using Callback = function image)>; void Load. Image. Async(string_view url, Callback callback); struct Image. View { void Show. Image. At. URL (string_view url) { Load. Image. Async(url, [this](auto url, auto img) { On. Image. Loaded(url, move(img)); UB На момент вызова колбека Image. View }); может быть разрушен. Нельзя вызывать } On. Image. Loaded private: void On. Image. Loaded(string_view url, unique_ptr image); };

Идиома weak this А если нельзя владеть Image. View через shared_ptr? struct Image. View Идиома weak this А если нельзя владеть Image. View через shared_ptr? struct Image. View : enable_shared_from_this { static auto Create() { return shared_ptr(new Image. View); } void Show. Image. At. URL (string_view url) { weak_ptr weak. Self = shared_from_this(); Load. Image. Async(url, [=](auto url, auto data) { if (auto strong. Self = weak. Self. lock()) strong. Self->On. Image. Loaded(url, move(data)); }); } private: Image. View() = default; void On. Image. Loaded(string_view url, unique_ptr image); }; Pimpl

Немного сахара в C++17 struct Image. View : enable_shared_from_this<Image. View> { static auto Create() Немного сахара в C++17 struct Image. View : enable_shared_from_this { static auto Create() { return shared_ptr(new Image. View); } void Show. Image. At. URL (string_view url) { Устраняется создание временного auto weak. Self = weak_from_this(); shared_ptr (меньше атомарных Load. Image. Async(url, [=](auto url, auto data) { операций) if (auto strong. Self = weak. Self. lock()) strong. Self->On. Image. Loaded(url, move(data)); }); } private: Image. View() = default; void On. Image. Loaded(string_view url, unique_ptr image); };

Еще больше сахара с Bind. Weak. Ptr struct Image. View : enable_shared_from_this<Image. View> { Еще больше сахара с Bind. Weak. Ptr struct Image. View : enable_shared_from_this { static auto Create() { return shared_ptr(new Image. View); } void Show. Image. At. URL (string_view url) { using namespace std: : placeholders; Load. Image. Async(url, Bind. Weak. Ptr(&Image. View: : On. Image. Loaded, shared_from_this(), _1, _2)); } Или weak_from_this() private: Image. View() = default; void On. Image. Loaded(string_view url, unique_ptr image); }; Bind weak ptr: https: //goo. gl/5 Nqu. DA

Пример - Universal. Ptr • Указатель, инкапсулирующий семантику владения ресурсом • No ownership • Пример - Universal. Ptr • Указатель, инкапсулирующий семантику владения ресурсом • No ownership • Unique/shared ownership • Применимость – альтернатива передаче по ссылке или указателю • Объекту нужен доступ к ресурсу, но не нужны права владения • Lifetime объекта не превышает lifetime ресурса • Клиент может передать объекту ресурс вместе с правами владения • Накладные расходы • Обертка над shared_ptr с соответствующими затратами на копирование

template <typename T> struct Universal. Ptr { constexpr Universal. Ptr() noexcept = default; constexpr template struct Universal. Ptr { constexpr Universal. Ptr() noexcept = default; constexpr Universal. Ptr(nullptr_t) noexcept {} template Universal. Ptr(U& r); template Universal. Ptr(U* p); template Universal. Ptr(std: : unique_ptr&& p); template Universal. Ptr(const std: : shared_ptr& p) noexcept; explicit operator bool()const noexcept; T& operator*()const noexcept; T* operator->()const noexcept; T* get()const noexcept; private: static constexpr void No. Delete(T*) noexcept {} std: : shared_ptr m_ptr; }; Полный фрагмент кода тут: https: //goo. gl/y. Flql 5

struct IShape { virtual ~IShape() = default; virtual void Draw()const = 0; }; struct struct IShape { virtual ~IShape() = default; virtual void Draw()const = 0; }; struct IShape. Factory { virtual ~IShape. Factory() = default; virtual unique_ptr Create. Shape(string name) = 0; }; struct Shape. Factory : IShape. Factory { /* implementation details */ }; struct Painter { Painter(Universal. Ptr factory) : m_factory(move(factory)) {} void Work. With. Shapes() { m_factory->Create. Shape("circle")->Draw(); } private: Universal. Ptr m_factory; }; Клиент использует фабрику не дольше, чем живет сам

void Painter. Without. Ownership() { Shape. Factory factory; Painter c 1(factory); Painter c 2(&factory); void Painter. Without. Ownership() { Shape. Factory factory; Painter c 1(factory); Painter c 2(&factory); c 1. Work. With. Shapes(); } Painter Get. Cli. Painter. With. Unique. Access. To. Factory() { return Painter(make_unique()); } vector Painter. With. Shared. Access. To. Factory() { auto f = make_shared(); Painter c 1(f), c 2(f), c 3(f); return { c 1, c 2, c 3 }; }

Пример – простой кеш документов string Get. File. Content(const char *file. Name); class Document. Пример – простой кеш документов string Get. File. Content(const char *file. Name); class Document. Storage : public enable_shared_from_this { using String. Ptr = shared_ptr; using String. Weak. Ptr = weak_ptr; map m_items; public: using Document. Content = function; Document. Content Get. Document. Content(const string &file. Name) { . . . } };

 Document. Content Get. Document. Content(const string &file. Name) { String. Ptr content; auto Document. Content Get. Document. Content(const string &file. Name) { String. Ptr content; auto it = m_items. find(file. Name); if (it != m_items. end()) content = it->second. lock(); if (!content) { weak_ptr weak. Self = shared_from_this(); auto deleter = [weak. Self, file. Name](string *s) { delete s; if (auto strong. Self = weak. Self. lock()) strong. Self->m_items. erase(file. Name); }; content. reset(new string(Get. File. Content(file. Name. c_str())), deleter); m_items. insert_or_assign(file. Name, content); } return [content] { return *content; }; } };

int main() { auto storage = make_shared<Document. Storage>(); { auto content 1 = storage->Get. int main() { auto storage = make_shared(); { auto content 1 = storage->Get. Document. Content("main. cpp"); cout << content 1(). length() << endl; auto content 2 = storage->Get. Document. Content("main. cpp"); cout << content 2(). length() << endl; } { auto content 1 = storage->Get. Document. Content("main. cpp"); cout << content 1(). length() << endl; } } Loading file content main. cpp 1736

std: : optional std: : optional

optional • Опциональное значение • Не использует динамическое выделение памяти • Применение • Значение, optional • Опциональное значение • Не использует динамическое выделение памяти • Применение • Значение, которого может и не быть • Результат поиска • Undefined-значение (если сам тип его не имеет) • Отложенное конструирование объекта • Поле класса не может быть проинициализировано в конструкторе • Ленивые вычисления • Простейшее информирование об ошибке

struct ICanvas; Прямоугольник с опциональными заливкой и обводкой struct Rect { void Draw(ICanvas & struct ICanvas; Прямоугольник с опциональными заливкой и обводкой struct Rect { void Draw(ICanvas & canvas) const { if (fill. Color) canvas. Begin. Solid. Fill(*fill. Color); canvas. Set. Line. Color(line. Color); canvas. Move. To(left, top); canvas. Line. To(left + width, top + height); canvas. Line. To(left, top); if (fill. Color) canvas. End. Fill(); } float left = 0. f, top = 0. f, width = 0. f, height = 0. f; optional fill. Color, line. Color; };

struct ICanvas { virtual ~ICanvas() = default; virtual void Begin. Solid. Fill(const RGBAColor& fill. struct ICanvas { virtual ~ICanvas() = default; virtual void Begin. Solid. Fill(const RGBAColor& fill. Color) = 0; virtual void End. Fill() = 0; virtual void Move. To(float x, float y) = 0; virtual void Set. Line. Color(const optional& line. Color) = 0; virtual void Line. To(float x, float y) = 0; }; void Draw. Picture(ICanvas& canvas) { Rect{ 10, 20, 10, palette: : YELLOW, palette: : RED }. Draw(canvas); Rect{ 5, 5, 10, nullopt, palette: : GREEN }. Draw(canvas); Rect{ 20, 5, 5, 20, palette: : BLUE }. Draw(canvas); }

Ленивое вычисление характеристик цифрового сигнала struct Signal { double Get. Max. Amplitude()const { if Ленивое вычисление характеристик цифрового сигнала struct Signal { double Get. Max. Amplitude()const { if (!m_max. Amplitude) { m_max. Amplitude = m_samples. empty() ? 0. 0 : *max_element(m_samples. begin(), m_samples. end()); } return *m_max. Amplitude; } void Set. Samples(vector samples) { m_samples = move(samples); m_max. Amplitude. reset(); } private: vector m_samples; mutable optional m_max. Amplitude; };

variant variant

variant • Тип, способный хранить значение одного из нескольких типов • Хранение по значению variant • Тип, способный хранить значение одного из нескольких типов • Хранение по значению • Примитивные или составные типы • Не требуется какая-либо связь между типами • Достоинства • Типобезопасность по сравнению с union • Не использует динамическое выделение памяти • Надежнее по сравнению с наивной реализацией

Пример – решение квадратного уравнения struct Not. AQudaratic. Equation {}; using Quadratic. Equation. Roots Пример – решение квадратного уравнения struct Not. AQudaratic. Equation {}; using Quadratic. Equation. Roots = variant< std: : monostate, // no roots double, // one root pair, // two roots Not. AQudaratic. Equation>; // not a quadratic equation

Решение квадратного уравнения Quadratic. Equation. Roots Solve(double a, double b, double c) { if Решение квадратного уравнения Quadratic. Equation. Roots Solve(double a, double b, double c) { if (abs(a) < std: : numeric_limits: : epsilon()) return Not. AQudaratic. Equation{}; else { auto disc = b * b - 4 * a * c; if (disc < 0) return std: : monostate{}; else if (disc < std: : numeric_limits: : epsilon()) return -b / (2 * a); else { auto sqrt. Disc = sqrt(disc); return make_pair((-b - sqrt. Disc) / (2 * a), (-b + sqrt. Disc) / (2 * a)); } } }

Обработка при помощи visitor class struct Result. Printer { void operator()(std: : monostate) { Обработка при помощи visitor class struct Result. Printer { void operator()(std: : monostate) { cout << "No real rootsn"; } void operator()(double x) { cout << "1 root: " << x << "n"; } void operator()(const pair& two. Roots) { cout << "2 roots: " << two. Roots. first << ", " << two. Roots. second << "n"; } void operator()(Not. AQudaratic. Equation) { cout << "This is not a quadratic equationn"; } }; visit(Result. Printer(), Solve(1, 0, -1));

Обработка при помощи get_if auto result = Solve(1, 0, -1); if (get_if<std: : monostate>(&result)) Обработка при помощи get_if auto result = Solve(1, 0, -1); if (get_if(&result)) cout << "No real rootsn"; else if (auto single. Root = get_if(&result)) cout << "1 root: " << *single. Root << "n"; else if (auto two. Roots = get_if>(&result)) cout << "2 roots: " << two. Roots->first << ", " << two. Roots->second << "n"; else if (get_if(&result)) cout << "This is not a quadratic equationn"; else cout << "Valueless by exceptionn"; get_if для boost: : variant https: //goo. gl/2 c. Fj 2 y

Обработка при помощи constexpr if template<class T> struct always_false : std: : false_type {}; Обработка при помощи constexpr if template struct always_false : std: : false_type {}; auto visitor = [](auto&& arg) { using T = decay_t; if constexpr (is_same_v) cout << "No real rootsn"; else if constexpr (is_same_v) cout << "1 root: " << arg << "n"; else if constexpr (is_same_v>) cout << "Two roots: " << arg. first << ", " << arg. second << "n"; else if constexpr (is_same_v) cout << "This is not a quadratic equationn"; else static_assert(always_false: : value, "non-exhaustive visitor!"); }; visit(visitor, Solve(1, 0, 0));

Algoritms, Ranges Algoritms, Ranges

 • Контейнеры • Хранят данные • Алгоритмы (~100 в C++17) • • • • Контейнеры • Хранят данные • Алгоритмы (~100 в C++17) • • • Поиск и подсчет элементов Модификация, копирование элементов, перестановки Сортировка и разделение Удаление элементов Сравнение Параллельная обработка (c++17) • Диапазоны • Обещают в C++20 • Есть в библиотеке boost: : range

Исходные данные enum class Gender : uint 8_t { Male, Female }; struct Person Исходные данные enum class Gender : uint 8_t { Male, Female }; struct Person { string name; short age; Gender gender; int salary; }; ostream& operator<<(ostream& out, const Person& p); int main() { const vector people = { { "Ivan", 25, Gender: : Male }, { "Peter", 35, Gender: : Male }, /* some more people*/ }; …

Вывод в stdout for (size_t i = 0; i < people. size(); ++i) { Вывод в stdout for (size_t i = 0; i < people. size(); ++i) { cout << people[i] << "n"; } for (auto & person : people) { cout << person << "n"; } copy(people, ostream_iterator(cout, "n"));

Вывести самого старого (raw loop) if (!people. empty()) { size_t oldest = 0; for Вывести самого старого (raw loop) if (!people. empty()) { size_t oldest = 0; for (size_t i = 1; i < people. size(); ++i) { if (people[i]. age > people[oldest]. age) { oldest = i; } } cout << "The oldest one is " << people[oldest] << "n"; } else { cout << "No peoplen"; }

Вывести самого старого (max_element) auto ordered. By. Age = [](auto & lhs, auto & Вывести самого старого (max_element) auto ordered. By. Age = [](auto & lhs, auto & rhs) { return lhs. age < rhs. age; }; auto oldest = max_element(people, ordered. By. Age); if (oldest != people. end()) cout << "The oldest one is " << *oldest << "n"; else cout << "No peoplen";

Вывести самого старого (C++17) auto ordered. By. Age = [](auto & lhs, auto & Вывести самого старого (C++17) auto ordered. By. Age = [](auto & lhs, auto & rhs) { return lhs. age < rhs. age; }; auto oldest = max_element(people, ordered. By. Age); oldest != people. end()) if ( cout << "The oldest one is " << *oldest << "n"; else cout << "No peoplen";

Вывести женщин от 20 до 30 лет, а потом мужчин от 25 до 40 Вывести женщин от 20 до 30 лет, а потом мужчин от 25 до 40 for (size_t i = 0; i < people. size(); ++i) { if (people[i]. gender == Gender: : Female && (people[i]. age >= 20 && people[i]. age <= 30)) { cout << people[i] << "n"; } } for (size_t i = 0; i < people. size(); ++i) { if (people[i]. gender == Gender: : Male && (people[i]. age >= 25 && people[i]. age <= 40)) { cout << people[i] << "n"; } }

Range based for (auto& person : people) { if ((person. gender == Gender: : Range based for (auto& person : people) { if ((person. gender == Gender: : Female) && (person. age >= 20 && person. age <= 30)) { cout << person << "n"; } } for (auto& person : people) { if ((person. gender == Gender: : Male) && (person. age >= 25 && person. age <= 40)) { cout << person << "n"; } }

Filtered-range auto By. Gender. And. Age = [](Gender g, int min. Age, int max. Filtered-range auto By. Gender. And. Age = [](Gender g, int min. Age, int max. Age) { return [=](auto& p) { return (p. gender == g) && p. age >= min. Age && p. age <= max. Age; }; }; auto To. Stdout = ostream_iterator(cout, "n"); copy(people | filtered(By. Gender. And. Age(Gender: : Female, 20, 30)), To. Stdout); copy(people | filtered(By. Gender. And. Age(Gender: : Male, 25, 40)), To. Stdout);

Ищем, есть ли женщины за 30 (raw for) bool has. Women. Older. Than 30 Ищем, есть ли женщины за 30 (raw for) bool has. Women. Older. Than 30 = false; for (size_t i = 0; i < people. size(); ++i) { if (people[i]. age > 30 && people[i]. gender == Gender: : Female) { has. Women. Older. Than 30 = true; break; } } if (has. Women. Older. Than 30) cout << "There are women older than 30n"; else cout << "There are no women above 30n";

Ищем, есть ли женщины за 30 (any_of) auto older. Than = [](int age) { Ищем, есть ли женщины за 30 (any_of) auto older. Than = [](int age) { return [=](auto& p) { return p. age > age; }; auto is. Female = [](auto& p) { return p. gender == Gender: : Female; }; if (any_of(people | filtered(older. Than(30)), is. Female)) cout << "There are women older than 30n"; else cout << "There are no women above 30n";

Паттерны проектирования в функциональном стиле Паттерны проектирования в функциональном стиле

Abstract Factory Abstract Factory

Продукт struct IProduct { virtual ~IProduct() = default; virtual void Foo() = 0; }; Продукт struct IProduct { virtual ~IProduct() = default; virtual void Foo() = 0; }; struct Concrete. Product : IProduct { Concrete. Product(int data): m_data(data) {} void Foo() override {} private: int m_data; };

struct IFactory { virtual ~IFactory() = default; virtual unique_ptr<IProduct> Create. Product() = 0; }; struct IFactory { virtual ~IFactory() = default; virtual unique_ptr Create. Product() = 0; }; void Client(IFactory& factory) { auto product = factory. Create. Product(); product->Foo(); } struct Concrete. Factory : IFactory { Concrete. Factory(int data) : m_data(data) {} unique_ptr Create. Product() override { return make_unique(m_data); } private: int m_data; }; void Test. Classic. Factory() { Concrete. Factory factory(42); Client(factory); } Интерфейс фабрики Клиентский код Полезный код Тестовый пример

Фабрика в функциональном стиле using Factory = function<unique_ptr<IProduct>()>; void Client(const Factory& make. Product) { Фабрика в функциональном стиле using Factory = function()>; void Client(const Factory& make. Product) { auto product = make. Product(); product->Foo(); } void Test. Functional. Factory() { Client([] {return make_unique(42); }

Команда Команда

Робот enum class Walk. Direction { North, South, West, East, }; struct Robot { Робот enum class Walk. Direction { North, South, West, East, }; struct Robot { void Turn. On(); void Turn. Off(); void Walk(Walk. Direction direction); void Stop(); … };

struct ICommand { virtual ~ICommand() = default; virtual void Execute() = 0; }; struct struct ICommand { virtual ~ICommand() = default; virtual void Execute() = 0; }; struct Menu { void Add. Item(string shortcut, string descr, unique_ptr && command); … }; struct Turn. On. Command : public ICommand { Turn. On. Command(CRobot & robot): m_robot(robot) {} void Execute() override { m_robot. Turn. On(); } private: Robot & m_robot; }; Robot robot; Menu menu; menu. Add. Item("on", "Turns the Robot on", make_unique(robot));

Команда в функциональном стиле struct Menu. FP { typedef std: : function<void()> Command; void Команда в функциональном стиле struct Menu. FP { typedef std: : function Command; void Add. Item(string shortcut, std: : string descr, const Command & command); … }; Robot robot; Menu. FP menu; menu. Add. Item("on", "Turns the Robot on", [&] { robot. Turn. On(); });

Спасибо за внимание! Спасибо за внимание!

Ссылки • Миграция на современный C++ 17 • Интервалы с C++ • С++ without Ссылки • Миграция на современный C++ 17 • Интервалы с C++ • С++ without new and delete https: //github. com/alexey-malov/Cpp. Meeting-Kazan 2017