Разделы презентаций


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

Содержание

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

Слайды и текст этой презентации

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

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

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

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

Слайд 3Семантика перемещения

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

Слайд 4Семантика перемещения
Позволяет компилятору заменить дорогостоящую операцию копирования менее дорогими перемещениями
Копирование

vector, string
Время: O(N)
Память: O(N) – для хранения копии
Может выбросить

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


Семантика перемещенияПозволяет компилятору заменить дорогостоящую операцию копирования менее дорогими перемещениямиКопирование vector, string Время: O(N)Память: O(N) – для

Слайд 5struct Person {
string name;
string surname;
};
struct Department {
string

name;
vector employees;
};

Department ReadDepartment(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;
}

C++’03

Может приводить к копированию всего Department

Копирование сотрудников при изменерии размеров контейнера

struct Person { string name; string surname;};struct Department { string name; vector employees;};Department ReadDepartment(istream& input) { Department

Слайд 6vector
Happy
new
year!
vector
H
a
p
p
y
n
e
w
Что происходит при копировании
y
e
a
r
H
a
p
p
y
n
e
w
y
e
a
r
Happy
new
year!

vectorHappynewyear!vectorHappynewЧто происходит при копированииyearHappynewyearHappynewyear!

Слайд 7vector
Happy
new
year!
vector
H
a
p
p
y
n
e
w
Что происходит при перемещении
y
e
a
r

vectorHappynewyear!vectorHappynewЧто происходит при перемещенииyear

Слайд 8struct Person {
string name;
string surname;
};
struct Department {
string

name;
vector employees;
};

Department ReadDepartment(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

struct Person { string name; string surname;};struct Department { string name; vector employees;};Department ReadDepartment(istream& input) { Department

Слайд 9Move-only типы
Для них операция копирования не имеет смысла
Полезно иметь возможность

перемещения значения от одного объекта
Возврат результата из функции
Передача аргумента в

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

Слайд 10namespace 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

namespace detail {template class Handle { HANDLE m_handle = INVALID;public: Handle() = default; explicit Handle(HANDLE handle =

Слайд 11 ~Handle() {
if (m_handle != INVALID) {

CloseHandle(m_handle);
}
}

explicit operator bool() const {

return m_handle != INVALID; }
operator HANDLE() const { return m_handle; }

void Close() {
if (!CloseHandle(m_handle)) {
m_handle = INVALID;
throw std::runtime_error("Failed to close handle");
}
m_handle = INVALID;
}
};
} // namespace detail

using FileHandle = detail::Handle;
~Handle() {  if (m_handle != INVALID) {   CloseHandle(m_handle);  } } explicit operator

Слайд 12FileHandle SafeOpenFile(LPCWSTR fileName) {
FileHandle fh(CreateFileW(fileName, 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 = SafeOpenFile(L"main.cpp");
DWORD fileSize = GetFileSize(f, nullptr);
if (fileSize != INVALID_FILE_SIZE)
cout << "File size: " << fileSize << "\n";
}

Пример использования

FileHandle SafeOpenFile(LPCWSTR fileName) { FileHandle fh(CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ,         nullptr,

Слайд 13Умные указатели

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

Слайд 14unique_ptr
Единолично владеет объектом через его указатель
Move-only
Нулевой оверхед + RAII
Совместим с

stl-контейнерами
Позволяет управлять массивом объектов в куче
Поддержка пользовательского deleter-а

R.I.P. auto_ptr

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

Слайд 15Идиома Pimpl (pointer to implementation)
Вместо хранения данных, класс хранит указатель

на структуру или класс с деталями реализации
Скрывает лишние зависимости из

заголовочного файла
Позволяет сократить время компиляции

Идиома Pimpl (pointer to implementation)Вместо хранения данных, класс хранит указатель на структуру или класс с деталями реализацииСкрывает

Слайд 16Пример – идиома Pimpl
#include "OpaqueObj.h"

struct OpaqueObj::Impl {
Impl(int data) :

m_data(data) {}
void Foo() { /* do something */ }

int m_data = 42;
};

OpaqueObj::OpaqueObj(int data)
: m_impl(new Impl(data)) {}

OpaqueObj::~OpaqueObj() { delete m_impl;}

void OpaqueObj::Foo() {
m_impl->Foo();
}

OpaqueObj.cpp

class OpaqueObj {
public:
OpaqueObj(int data);
~OpaqueObj();
 
void Foo();
private:
struct Impl;
Impl* m_impl;
};

OpaqueObj.h

Проблема – требуется реализовать или запретить конструктор копирования и оператор присваивания


Слайд 17Идиома Pimpl с unique_ptr
#include "OpaqueObj.h"
 
struct OpaqueObj::Impl {
Impl(int data) :

m_data(data) {} 
void Foo() { /* do something */ }

int m_data = 42;
};
 
OpaqueObj::OpaqueObj(int data)
: m_impl(make_unique(data)){}

OpaqueObj::~OpaqueObj() = default;

void OpaqueObj::Foo() {
m_impl->Foo();
}

OpaqueObj.cpp

class OpaqueObj {
public:
OpaqueObj(int data);
~OpaqueObj();
 
void Foo();
private:
struct Impl;
unique_ptr m_impl;
};

OpaqueObj.h

Приятный бонус: OpaqueObj из коробки стал Move-only типом


Слайд 18Умное управление ресурсами библиотеки языка C
typedef struct tagData {
int

value;
} Data;
 
Data* AllocateData();
void DoSomethingWithData(Data *data, int x);
void DeallocateData(Data* data);

Умное управление ресурсами библиотеки языка Ctypedef struct tagData { int value;} Data; Data* AllocateData();void DoSomethingWithData(Data *data, int x);void

Слайд 19int CalculateX(int value);




bool Foo() {
Data *p = AllocateData();
if

(!p) {
cout

return false;
}
if (p->value == 42) {
DeallocateData(p);
return true;
}

DoSomethingWithData(p, CalculateX(p->value));
DeallocateData(p);
return false;
}

Код по-прежнему содержит проблему

int CalculateX(int value);bool Foo() { Data *p = AllocateData(); if (!p) {  cout value == 42)

Слайд 20int CalculateX(int value) {
if (value < 0) throw std::invalid_argument("Invalid

argument");
return value + 1;
}

bool Foo() {
Data *p =

AllocateData();
if (!p) {
cout << "Failed to allocated data\n";
return false;
}
if (p->value == 42) {
DeallocateData(p);
return true;
}

DoSomethingWithData(p, CalculateX(p->value));
DeallocateData(p);
return false;
}

Если CalculateX выбросит исключение, DeallocateData вызван не будет


Слайд 21struct DataDeleter {
void operator()(Data *data) const noexcept {

DeallocateData(data);
}
};
using DataPtr = std::unique_ptr;

DataPtr SafeAllocateData() {
if (DataPtr

p{AllocateData()})
return p;
throw std::runtime_error("Failed to allocate data");
}

Пользовательский deleter

struct DataDeleter { void operator()(Data *data) const noexcept {  DeallocateData(data); }};using DataPtr = std::unique_ptr;DataPtr SafeAllocateData() {

Слайд 22bool Foo() {
Data *p = AllocateData();
if (!p) {

cout

}
if (p->value == 42) {
DeallocateData(p);
return true;
}

DoSomethingWithData(p, CalculateX(p->value));
DeallocateData(p);
return false;
}

Было

bool Foo() { Data *p = AllocateData(); if (!p) {  cout value == 42) {

Слайд 23bool Foo() {
try {
auto p = SafeAllocateData();

if (p->value == 42)
return true;

DoSomethingWithData(p.get(), CalculateX(p->value));
} catch (std::exception const &e) {
cout << e.what() << "\n";
}
return false;
}

Стало

bool Foo() { try {  auto p = SafeAllocateData();  if (p->value == 42)

Слайд 24shared_ptr
Умный указатель, основанный на подсчете ссылок
Обеспечивает совместное владение объектом
Возможность управления

не только памятью
Накладные расходы
Память для хранения счетчиков
Thread-safe подсчет ссылок

shared_ptrУмный указатель, основанный на подсчете ссылокОбеспечивает совместное владение объектомВозможность управления не только памятьюНакладные расходыПамять для хранения счетчиковThread-safe

Слайд 25weak_ptr
Слабая ссылка на объект
Не влияет на время жизни
Автоматически обнуляется после

удаления объекта
Пока объект жив, позволяет получить shared_ptr на него
Решает проблему

циклических ссылок и висячих указателей

Master

Slave

weak_ptrСлабая ссылка на объектНе влияет на время жизниАвтоматически обнуляется после удаления объектаПока объект жив, позволяет получить shared_ptr

Слайд 26enable_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
Защита от преждевременного удаления при вызове внешнего кода
enable_shared_from_thisПозволяет объекту, управляемому shared_ptr, безопасно создать экземпляр shared_ptr на самого себяshared_from_this()weak_from_this () (C++ 17)Нельзя вызывать shared_from_this() из

Слайд 27using NodePtr = shared_ptr;
 
struct Node : enable_shared_from_this {
void

AddChild(const NodePtr& node) {
auto self = shared_from_this();

if (node == self || IsDescendantOf(node))
throw invalid_argument("Can't add self or ancestor");
 
if (m_children.emplace(node).second) {
if (auto oldParent = node->GetParent()) oldParent->m_children.erase(node);
node->m_parent = self;
}
}
NodePtr GetParent()const { return m_parent.lock(); }
bool IsDescendantOf(const NodePtr& node)const {
auto self = shared_from_this();
for (auto x = node->GetParent(); x; x = x->GetParent())
if (x == self) return true;
return false;
}
private:
weak_ptr m_parent;
unordered_set m_children;
};

Слайд 28struct Image { /* some image data */ };

using Callback

= function;
void LoadImageAsync(string_view url, Callback callback);

struct ImageView
{

void ShowImageAtURL(string_view url) {
/* Загрузить изображение асинхронно и вызвать OnImageLoaded */
}
private:
void OnImageLoaded(string_view url, unique_ptr image);
};

???

Задача: асинхронная загрузка изображения в GUI-приложении

struct Image { /* some image data */ };using Callback = function;void LoadImageAsync(string_view url, Callback callback);struct ImageView{

Слайд 29Решение, которое (иногда) не работает Почему?
using Callback = function

image)>;
void LoadImageAsync(string_view url, Callback callback);

struct ImageView
{
void ShowImageAtURL (string_view url)

{
LoadImageAsync(url, [this](auto url, auto img) {
OnImageLoaded(url, move(img));
});
}
private:
void OnImageLoaded(string_view url, unique_ptr image);
};

UB На момент вызова колбека ImageView может быть разрушен. Нельзя вызывать OnImageLoaded

Решение, которое (иногда) не работает Почему?using Callback = function;void LoadImageAsync(string_view url, Callback callback);struct ImageView{ void ShowImageAtURL (string_view

Слайд 30Идиома weak this
struct ImageView : enable_shared_from_this
{
static auto Create() {

return shared_ptr(new ImageView);
}
void ShowImageAtURL (string_view url) {

weak_ptr weakSelf = shared_from_this();
LoadImageAsync(url, [=](auto url, auto data) {
if (auto strongSelf = weakSelf.lock())
strongSelf->OnImageLoaded(url, move(data));
});
}
private:
ImageView() = default;
void OnImageLoaded(string_view url, unique_ptr image);
};

А если нельзя владеть ImageView через shared_ptr?

Pimpl

Идиома weak thisstruct ImageView : enable_shared_from_this{ static auto Create() {  return shared_ptr(new ImageView); } void ShowImageAtURL

Слайд 31Немного сахара в C++17
struct ImageView : enable_shared_from_this
{
static auto Create()

{
return shared_ptr(new ImageView);
}
void ShowImageAtURL (string_view url)

{
auto weakSelf = weak_from_this();
LoadImageAsync(url, [=](auto url, auto data) {
if (auto strongSelf = weakSelf.lock())
strongSelf->OnImageLoaded(url, move(data));
});
}
private:
ImageView() = default;
void OnImageLoaded(string_view url, unique_ptr image);
};
Немного сахара в C++17struct ImageView : enable_shared_from_this{ static auto Create() {  return shared_ptr(new ImageView); } void

Слайд 32Еще больше сахара с BindWeakPtr
struct ImageView : enable_shared_from_this
{
static auto

Create() {
return shared_ptr(new ImageView);
}
void ShowImageAtURL (string_view

url) {
using namespace std::placeholders;
LoadImageAsync(url, BindWeakPtr(&ImageView::OnImageLoaded,
shared_from_this(), _1, _2));
}
private:
ImageView() = default;
void OnImageLoaded(string_view url, unique_ptr image);
};

Или weak_from_this()

Bind weak ptr: https://goo.gl/5NquDA

Еще больше сахара с BindWeakPtrstruct ImageView : enable_shared_from_this{ static auto Create() {  return shared_ptr(new ImageView); }

Слайд 33Пример - UniversalPtr
Указатель, инкапсулирующий семантику владения ресурсом
No ownership
Unique/shared ownership
Применимость –

альтернатива передаче по ссылке или указателю
Объекту нужен доступ к ресурсу,

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

Слайд 34template
struct UniversalPtr
{
constexpr UniversalPtr() noexcept = default;
  constexpr

UniversalPtr(nullptr_t) noexcept {}
 
template UniversalPtr(U& r);
 template

U> UniversalPtr(U* p);
  template UniversalPtr(std::unique_ptr&& p);
  template UniversalPtr(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 NoDelete(T*) noexcept {} 
std::shared_ptr m_ptr;
};

Полный фрагмент кода тут: https://goo.gl/yFlql5

template struct UniversalPtr{ constexpr UniversalPtr() noexcept = default;  constexpr UniversalPtr(nullptr_t) noexcept {}  template UniversalPtr(U& r);  template UniversalPtr(U*

Слайд 35struct IShape {
virtual ~IShape() = default;
virtual void Draw()const

= 0;
};
struct IShapeFactory {
virtual ~IShapeFactory() = default;
virtual unique_ptr

CreateShape(string name) = 0;
};
struct ShapeFactory : IShapeFactory { /* implementation details */ };

struct Painter {
Painter(UniversalPtr factory)
:m_factory(move(factory)) {}

void WorkWithShapes() {
m_factory->CreateShape("circle")->Draw();
}
private:
UniversalPtr m_factory;
};

Слайд 36void PainterWithoutOwnership()
{
ShapeFactory factory;
Painter c1(factory);
Painter c2(&factory);
c1.WorkWithShapes();
}

Painter GetCliPainterWithUniqueAccessToFactory()
{

return Painter(make_unique());
}

vector PainterWithSharedAccessToFactory()
{
auto f = make_shared();
Painter c1(f), c2(f),

c3(f);
return { c1, c2, c3 };
}
void PainterWithoutOwnership(){ ShapeFactory factory; Painter c1(factory); Painter c2(&factory); c1.WorkWithShapes();}Painter GetCliPainterWithUniqueAccessToFactory(){ return Painter(make_unique());}vector PainterWithSharedAccessToFactory(){ auto f = make_shared();

Слайд 37string GetFileContent(const char *fileName);

class DocumentStorage : public enable_shared_from_this {
using

StringPtr = shared_ptr;
using StringWeakPtr = weak_ptr;
map m_items;
public:

using DocumentContent = function;

DocumentContent GetDocumentContent(const string &fileName) {
...
}
};

Пример – простой кеш документов

string GetFileContent(const char *fileName);class DocumentStorage : public enable_shared_from_this { using StringPtr = shared_ptr; using StringWeakPtr = weak_ptr;

Слайд 38 DocumentContent GetDocumentContent(const string &fileName) {
StringPtr content;

auto it = m_items.find(fileName);
if (it != m_items.end())

content = it->second.lock();

if (!content) {
weak_ptr weakSelf = shared_from_this();
auto deleter = [weakSelf, fileName](string *s) {
delete s;
if (auto strongSelf = weakSelf.lock())
strongSelf->m_items.erase(fileName);
};
content.reset(new string(GetFileContent(fileName.c_str())), deleter);
m_items.insert_or_assign(fileName, content);
}

return [content] { return *content; };
}
};
DocumentContent GetDocumentContent(const string &fileName) {  StringPtr content;  auto it = m_items.find(fileName);  if (it

Слайд 39int main() {
auto storage = make_shared();
{
auto

content1 = storage->GetDocumentContent("main.cpp");
cout

auto content2 = storage->GetDocumentContent("main.cpp");
cout << content2().length() << endl;
}
{
auto content1 = storage->GetDocumentContent("main.cpp");
cout << content1().length() << endl;
}
}

Loading file content main.cpp
1736
1736
Loading file content main.cpp
1736

int main() { auto storage = make_shared(); {  auto content1 = storage->GetDocumentContent(

Слайд 40std::optional

std::optional

Слайд 41optional
Опциональное значение
Не использует динамическое выделение памяти
Применение
Значение, которого может и не

быть
Результат поиска
Undefined-значение (если сам тип его не имеет)
Отложенное конструирование объекта
Поле

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

Слайд 42struct ICanvas;

struct Rect
{
void Draw(ICanvas & canvas) const {

if (fillColor) canvas.BeginSolidFill(*fillColor);
 
canvas.SetLineColor(lineColor);
canvas.MoveTo(left, top);
canvas.LineTo(left

+ width, top);
canvas.LineTo(left + width, top + height);
canvas.LineTo(left, top + height);
canvas.LineTo(left, top);
 
if (fillColor) canvas.EndFill();
}
 
float left = 0.f, top = 0.f, width = 0.f, height = 0.f;
optional fillColor, lineColor;
};

Прямоугольник с опциональными заливкой и обводкой

struct ICanvas;struct Rect{ void Draw(ICanvas & canvas) const {  if (fillColor) canvas.BeginSolidFill(*fillColor);   canvas.SetLineColor(lineColor);  canvas.MoveTo(left,

Слайд 43struct ICanvas
{
virtual ~ICanvas() = default;
virtual void BeginSolidFill(const RGBAColor&

fillColor) = 0;
virtual void EndFill() = 0;
virtual void

MoveTo(float x, float y) = 0;
virtual void SetLineColor(const optional& lineColor) = 0;
virtual void LineTo(float x, float y) = 0;
};

void DrawPicture(ICanvas& canvas)
{
Rect{ 10, 10, 20, 10, palette::YELLOW, palette::RED }.Draw(canvas);
Rect{ 5, 5, 10, 10, nullopt, palette::GREEN }.Draw(canvas);
Rect{ 20, 5, 5, 20, palette::BLUE }.Draw(canvas);
}

struct ICanvas{ virtual ~ICanvas() = default; virtual void BeginSolidFill(const RGBAColor& fillColor) = 0; virtual void EndFill() =

Слайд 44struct Signal
{
double GetMaxAmplitude()const {
if (!m_maxAmplitude) {

m_maxAmplitude = m_samples.empty() ? 0.0

: *max_element(m_samples.begin(), m_samples.end());
}
return *m_maxAmplitude;
}

void SetSamples(vector samples) {
m_samples = move(samples);
m_maxAmplitude.reset();
}
private:
vector m_samples;
mutable optional m_maxAmplitude;
};

Ленивое вычисление характеристик цифрового сигнала

struct Signal{ double GetMaxAmplitude()const {  if (!m_maxAmplitude) {   m_maxAmplitude = m_samples.empty() ? 0.0

Слайд 45variant

variant

Слайд 46variant
Тип, способный хранить значение одного из нескольких типов
Хранение по значению
Примитивные

или составные типы
Не требуется какая-либо связь между типами
Достоинства
Типобезопасность по сравнению

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

Слайд 47Пример – решение квадратного уравнения
struct NotAQudaraticEquation {};
using QuadraticEquationRoots = variant

std::monostate, // no roots
double, // one root

pair, // two roots
NotAQudaraticEquation>; // not a quadratic equation
 
Пример – решение квадратного уравненияstruct NotAQudaraticEquation {};using QuadraticEquationRoots = variant; // not a quadratic equation 

Слайд 48Решение квадратного уравнения
QuadraticEquationRoots Solve(double a, double b, double c) {

if (abs(a) < std::numeric_limits::epsilon())
return NotAQudaraticEquation{};
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 sqrtDisc = sqrt(disc);
return make_pair((-b - sqrtDisc) / (2 * a), (-b + sqrtDisc) / (2 * a));
}
}
}
Решение квадратного уравненияQuadraticEquationRoots Solve(double a, double b, double c) { if (abs(a) < std::numeric_limits::epsilon())  return NotAQudaraticEquation{};

Слайд 49Обработка при помощи visitor class
struct ResultPrinter {
void operator()(std::monostate) {

cout

{
cout << "1 root:" << x << "\n";
}
void operator()(const pair& twoRoots) {
cout << "2 roots: " << twoRoots.first << ", " << twoRoots.second << "\n";
}
void operator()(NotAQudaraticEquation) {
cout << "This is not a quadratic equation\n";
}
};

visit(ResultPrinter(), Solve(1, 0, -1));
Обработка при помощи visitor classstruct ResultPrinter { void operator()(std::monostate) {  cout

Слайд 50Обработка при помощи get_if
auto result = Solve(1, 0, -1);

if (get_if(&result))

cout

cout << "1 root:" << *singleRoot << "\n";
else if (auto twoRoots = get_if>(&result))
cout << "2 roots: " << twoRoots->first << ", " << twoRoots->second << "\n";
else if (get_if(&result))
cout << "This is not a quadratic equation\n";
else
cout << "Valueless by exception\n";

get_if для boost::variant https://goo.gl/2cFj2y

Обработка при помощи get_ifauto result = Solve(1, 0, -1);if (get_if(&result)) cout

Слайд 51Обработка при помощи 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 roots\n";
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 equation\n";
else
static_assert(always_false::value, "non-exhaustive visitor!");
};
visit(visitor, Solve(1, 0, 0));
Обработка при помощи constexpr iftemplate struct always_false : std::false_type {};auto visitor = [](auto&& arg) { using T

Слайд 52Algoritms, Ranges

Algoritms, Ranges

Слайд 53Контейнеры
Хранят данные
Алгоритмы (~100 в C++17)
Поиск и подсчет элементов
Модификация, копирование элементов,

перестановки
Сортировка и разделение
Удаление элементов
Сравнение
Параллельная обработка (c++17)
Диапазоны
Обещают в C++20
Есть в библиотеке

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

Слайд 54Исходные данные
enum class Gender : uint8_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*/
};

};
Исходные данныеenum class Gender : uint8_t { Male, Female }; struct Person { string name; short age; Gender

Слайд 55Вывод в stdout
for (size_t i = 0; i < people.size();

++i) {
cout

: people) {
cout << person << "\n";
}

 
copy(people, ostream_iterator(cout, "\n"));
Вывод в stdoutfor (size_t i = 0; i < people.size(); ++i) { cout

Слайд 56Вывести самого старого (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 people\n";
}
Вывести самого старого (raw loop)if (!people.empty()) { size_t oldest = 0; for (size_t i = 1; i

Слайд 57Вывести самого старого (max_element)
auto orderedByAge = [](auto & lhs, auto

& rhs) {
return lhs.age < rhs.age;
};

auto oldest = max_element(people,

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

Слайд 58Вывести самого старого (C++17)
auto orderedByAge = [](auto & lhs, auto

& rhs) {
return lhs.age < rhs.age;
};


oldest !=

people.end())
cout << "The oldest one is " << *oldest << "\n";
else
cout << "No people\n";

auto oldest = max_element(people, orderedByAge);

if (

Вывести самого старого (C++17)auto orderedByAge = [](auto & lhs, auto & rhs) { return lhs.age < rhs.age;};

Слайд 59Вывести женщин от 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";
}
}
Вывести женщин от 20 до 30 лет, а потом мужчин от 25 до 40for (size_t i =

Слайд 60Range based for
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";
}
}
Range based forfor (auto& person : people) { if ((person.gender == Gender::Female) &&    (person.age

Слайд 61Filtered-range
auto ByGenderAndAge = [](Gender g, int minAge, int maxAge) {

return [=](auto& p) {
return (p.gender == g)

&& p.age >= minAge && p.age <= maxAge;
};
};

auto ToStdout = ostream_iterator(cout, "\n");
copy(people | filtered(ByGenderAndAge(Gender::Female, 20, 30)), ToStdout);
copy(people | filtered(ByGenderAndAge(Gender::Male, 25, 40)), ToStdout);
Filtered-rangeauto ByGenderAndAge = [](Gender g, int minAge, int maxAge) { return [=](auto& p) {   return

Слайд 62Ищем, есть ли женщины за 30 (raw for)
bool hasWomenOlderThan30 =

false;
for (size_t i = 0; i < people.size(); ++i) {

if (people[i].age > 30 && people[i].gender == Gender::Female) {
hasWomenOlderThan30 = true;
break;
}
}

if (hasWomenOlderThan30)
cout << "There are women older than 30\n";
else
cout << "There are no women above 30\n";
Ищем, есть ли женщины за 30 (raw for)bool hasWomenOlderThan30 = false;for (size_t i = 0; i <

Слайд 63Ищем, есть ли женщины за 30 (any_of)
auto olderThan = [](int

age) {
return [=](auto& p) { return p.age > age;

};
};
auto isFemale = [](auto& p) { return p.gender == Gender::Female; };

if (any_of(people | filtered(olderThan(30)), isFemale))
cout << "There are women older than 30\n";
else
cout << "There are no women above 30\n";
Ищем, есть ли женщины за 30 (any_of)auto olderThan = [](int age) { return [=](auto& p) { return

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

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

Слайд 65Abstract Factory

Abstract Factory

Слайд 66Продукт
struct IProduct {
virtual ~IProduct() = default;
virtual void Foo()

= 0;
};

struct ConcreteProduct : IProduct {
ConcreteProduct(int data):m_data(data) {}
void

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

Слайд 67struct IFactory {
virtual ~IFactory() = default;
virtual unique_ptr CreateProduct()

= 0;
};
void Client(IFactory& factory) {
auto product = factory.CreateProduct();
product->Foo();
}
struct

ConcreteFactory : IFactory {
ConcreteFactory(int data) :m_data(data) {}
unique_ptr CreateProduct() override {
return make_unique(m_data);
}
private:
int m_data;
};

void TestClassicFactory() {
ConcreteFactory factory(42);
Client(factory);
}

Интерфейс фабрики

Клиентский код

Полезный код

Тестовый пример

struct IFactory { virtual ~IFactory() = default; virtual unique_ptr CreateProduct() = 0;};void Client(IFactory& factory) { auto product

Слайд 68using Factory = function;

void Client(const Factory& makeProduct) {
auto product

= makeProduct();
product->Foo();
}

void TestFunctionalFactory() {
Client([] {return make_unique(42); });
}
Фабрика в

функциональном стиле
using Factory = function;void Client(const Factory& makeProduct) { auto product = makeProduct(); product->Foo();}void TestFunctionalFactory() { Client([] {return

Слайд 69Команда

Команда

Слайд 70enum class WalkDirection { North, South, West, East, };
 
struct Robot

{
void TurnOn();
void TurnOff();
void Walk(WalkDirection direction);
void Stop();


};

Робот

enum class WalkDirection { North, South, West, East, }; struct Robot { void TurnOn(); void TurnOff(); void Walk(WalkDirection

Слайд 71struct ICommand {
virtual ~ICommand() = default;
virtual void Execute()

= 0;
};
struct Menu {
void AddItem(string shortcut, string descr, unique_ptr

&& command);

};
struct TurnOnCommand : public ICommand {
TurnOnCommand(CRobot & robot): m_robot(robot) {}
void Execute() override {
m_robot.TurnOn();
}
private:
Robot & m_robot;
};

Robot robot;
Menu menu;
menu.AddItem("on", "Turns the Robot on", make_unique(robot));

struct ICommand { virtual ~ICommand() = default; virtual void Execute() = 0;};struct Menu { void AddItem(string shortcut,

Слайд 72struct MenuFP {
typedef std::function Command;
void AddItem(string shortcut, std::string

descr, const Command & command);

};

Robot robot;
MenuFP menu;
menu.AddItem("on", "Turns the

Robot on", [&] { robot.TurnOn(); });

Команда в функциональном стиле

struct MenuFP { typedef std::function Command; void AddItem(string shortcut, std::string descr, const Command & command); …};Robot robot;MenuFP

Слайд 73Спасибо за внимание!

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

Слайд 74Ссылки
Миграция на современный C++ 17
Интервалы с C++
С++ without new and

delete

https://github.com/alexey-malov/CppMeeting-Kazan2017

СсылкиМиграция на современный C++ 17Интервалы с C++С++ without new and deletehttps://github.com/alexey-malov/CppMeeting-Kazan2017

Обратная связь

Если не удалось найти и скачать доклад-презентацию, Вы можете заказать его на нашем сайте. Мы постараемся найти нужный Вам материал и отправим по электронной почте. Не стесняйтесь обращаться к нам, если у вас возникли вопросы или пожелания:

Email: Нажмите что бы посмотреть 

Что такое TheSlide.ru?

Это сайт презентации, докладов, проектов в PowerPoint. Здесь удобно  хранить и делиться своими презентациями с другими пользователями.


Для правообладателей

Яндекс.Метрика