Программирование. Variadic Templates. LSP

Содержание

Слайд 2

Содержание

Variadic templates
Perfect Forwarding
LSP

Содержание Variadic templates Perfect Forwarding LSP

Слайд 3

Variadic Templates

Объявление переменного числа типов
template
Объявление набора параметров типов, заданных Args
double

Variadic Templates Объявление переменного числа типов template Объявление набора параметров типов, заданных
f(Args... args)
Распаковка кортежа параметров
g(args...);

Слайд 4

Распаковка кортежа

template void f(Us... pargs) {}
template void g(Ts... args) {
f(&args...);

Распаковка кортежа template void f(Us... pargs) {} template void g(Ts... args) {
// “&args...” is a pack expansion
// “&args” is its pattern
}
g(1, 0.2, "a"); // Ts... args expand to int E1, double E2, const char* E3
// &args... expands to &E1, &E2, &E3
// Us... pargs expand to int* E1, double* E2, const char** E3

Слайд 5

Распаковка кортежа (2)

f(&args...); // expands to f(&E1, &E2, &E3)
f(n, ++args...); // expands

Распаковка кортежа (2) f(&args...); // expands to f(&E1, &E2, &E3) f(n, ++args...);
to f(n, ++E1, ++E2, ++E3);
f(++args..., n); // expands to f(++E1, ++E2, ++E3, n);
f(const_cast(&args)...);
// f(const_cast(&X1), const_cast(&X2), const_cast(&X3))
f(h(args...) + args...); // expands to
// f(h(E1,E2,E3) + E1, h(E1,E2,E3) + E2, h(E1,E2,E3) + E3)

Слайд 6

Распаковка кортежа (3)

(const args&..) // -> (const T1& arg1, const T2& arg2,

Распаковка кортежа (3) (const args&..) // -> (const T1& arg1, const T2&
...)
((f(args) + g(args))...) // -> (f(arg1) + g(arg1), f(arg2) + g(arg2), ...)
(f(args...) + g(args...)) // -> (f(arg1, arg2,...) + g(arg1, arg2, ...))

Слайд 7

Использование лямбда

template
void f(Args... args) {
auto lm = [&, args...]{ return

Использование лямбда template void f(Args... args) { auto lm = [&, args...]{
g(args...); };
lm();
}

Список захвата лямбда-функции может принимать кортеж типов

Слайд 8

Пример: Сумма

template
double sum(T t) {
return t;
}
// Рекурсия: поэлементная развертка

Пример: Сумма template double sum(T t) { return t; } // Рекурсия:
кортежа
template
double sum(T t, Rest... rest) {
return t + sum(rest...);
}

Слайд 9

Пример №2

template
T square(T t) { return t * t; }
//

Пример №2 template T square(T t) { return t * t; }
Our base case just returns the value.
template
double power_sum(T t) { return t; }
// Our new recursive case.
template
double power_sum(T t, Rest... rest) {
return t + power_sum(square(rest)...);
}

power_sum(2.0, 4.0, 6.0);

Слайд 10

Принцип LSP

 

class Rectangle
{
public:
void SetWidth(int w) { w_ = w; }
void

Принцип LSP class Rectangle { public: void SetWidth(int w) { w_ =
SetHeight(int h) { h_ = h; }
protected:
int w_;
int h_;
};

Слайд 11

LSP: Пример

Геометрические фигуры: прямоугольник, квадрат
Квадрат – более «специализированное» определение прямоугольника
Методы Set/GetWidth, Set/GetHeight,

LSP: Пример Геометрические фигуры: прямоугольник, квадрат Квадрат – более «специализированное» определение прямоугольника
GetArea()
Квадрат –> w == h ?

Rectangle

Quad

Слайд 12

LSP: Реализация Rectangle (1)

class Rectangle
{
public:
void SetWidth(int w) { w_ = w;

LSP: Реализация Rectangle (1) class Rectangle { public: void SetWidth(int w) {
}
void SetHeight(int h) { h_ = h; }
int GetArea() { return w_ * h_; }
protected:
int w_;
int h_;
};

Невиртуальные методы не будут корректно работать для Quad

Слайд 13

LSP: Реализация Rectangle (2)

class Rectangle
{
public:
virtual void SetWidth(int w) { w_ =

LSP: Реализация Rectangle (2) class Rectangle { public: virtual void SetWidth(int w)
w; }
virtual void SetHeight(int h) { h_ = h; }
int GetArea() { return w_ * h_; }
protected:
int w_;
int h_;
};

С точки зрения семантики класса эти методы НЕ ДОЛЖНЫ БЫТЬ виртуальными

Слайд 14

LSP: Реализация Quad

class Quad : public Rectangle
{
public:
void SetWidth(int w) { w_

LSP: Реализация Quad class Quad : public Rectangle { public: void SetWidth(int
= w; h_ = w; }
void SetHeight(int w) { w_ = w; h_ = w; }
};

Семантика quad соблюдена

Слайд 15

Нарушение LSP

void g(Rectangle *p)
{
p->SetHeight(5);
p->SetWidth(4);
assert(p->GetArea() == 20);
}

Ошибки проектирования иерархии
При реализации

Нарушение LSP void g(Rectangle *p) { p->SetHeight(5); p->SetWidth(4); assert(p->GetArea() == 20); }
Quad потребовалось сделать изменения в базовом Rectangle (+ virtual)
Семантика методов базового класса поменялась
Ранее разделенные методы стали зависимы
Quad не является Rectangle в данном контексте