1
2 
Статический и 
динамический 
полиморфизм в C++ 
Дмитрий Леванов 
Ведущий разработчик Крипта
3 
Крипта 
 Отвечает на вопрос «Кто?» 
 Определяет интересы по поведению в 
интернете 
 Используется для таргетинга рекламы 
 От др.-греч. κρυπτή — крытый подземный ход, 
тайник
4 
Как учили Крипту 
+ Логи 
Обучение Контроль 
Матрикснет
5 
Крипта
6 
Разработка Крипты 
 Много логов в разных форматах 
 Сложные цепочки обработки 
 Высокие требования к производительности 
 Много одинаковой похожей логики 
 Хочется делать всё однообразно
7 
Полиморфизм
8 
Полиморфизм 
 Способ поставить в соответствие некой 
грамматической конструкции контекстно- 
зависимую семантику 
или, по-русски: 
 Текст программы [почти] один и тот же, а 
смысл разный
9 
Виртуальный полиморфизм 
struct Base { 
virtual void do() { std::cout << “base”; } 
}; 
struct Derived : public Base { 
virtual void do() { std::cout << “derived”; } 
}; 
Base* b = new Derived(); 
b->do(); // derived 
 ООП-шненько 
 Типобезопасно 
 Работают фичи, зависящие от _vptr
Виртуальный полиморфизм: минусы 
 Медленный вызов методов 
 Надо поддерживать иерархию классов 
 Приходится иметь дело с T* или T& 
 Грабли с виртуальными методами 
 Статический метод не может быть виртуальным 
 Инвариантность параметров 
10
11 
Зачастую все сводится к… 
void for_each(const vector<int>& v, const Handler& h) { 
for (int i : v) { 
h.handle(i); 
} 
} 
//... 
vector<int> vect = {1,2,3}; 
MyHandler handler; 
for_each(vect, handler);
12 
То же самое, но лучше 
template<typename Handler> 
void for_each(const vector<int>& v, const Handler& h) { 
for (int i : v) { 
h.handle(i); 
} 
} 
//... 
vector<int> vect = {1,2,3}; 
MyHandler handler; 
for_each(vect, handler);
13 
Продолжаем улучшать 
template<typename Handler> 
void for_each(const vector<int>& v, const Handler& h) { 
for (int i : v) { 
h(i); 
} 
} 
//... 
vector<int> vect = {1,2,3}; 
MyHandler handler; 
for_each(vect, handler);
14 
Совсем хорошо 
template<typename Handler> 
void for_each(const vector<int>& v, const Handler& h) { 
for (int i : v) { 
h(i); 
} 
} 
//... 
vector<int> vect = {1,2,3}; 
for_each(vect, [](int i){ cout << i; });
15 
Или так 
template<typename Handler> 
void for_each(const vector<int>& v) { 
for (int i : v) { 
Handler::handle(i); 
} 
} 
//... 
vector<int> vect = {1,2,3}; 
MyHandler handler; 
for_each<MyHandler>(vect);
16 
Статический полиморфизм: плюсы 
 Типобезопасно 
 Быстрый вызов методов 
 Не надо наследоваться 
 Не надо иметь дело с указателями 
 Контрвариантность параметров 
 Можно использовать лямбды
Статический полиморфизм: минусы 
17 
 Нельзя положить в коллекцию 
 Сложно проверять правильность кода 
 Медленно компилируется 
 Может распухнуть бинарник 
 Нет поддержки концептов 
 Есть ограничения компилятора 
 Не во всех IDE правильно работает 
автокомплит
18 
Синтаксис иногда довольно 
странный… 
this->do();
19 
Синтаксис иногда довольно 
странный… 
this->do(); 
typename T::iter f(typename T::iter i);
20 
Синтаксис иногда довольно 
странный… 
this->do(); 
typename T::iter f(typename T::iter i); 
this->template do<T>(); // WTF???
21 
Замещение 
виртуального 
полиморфизма 
статическим
«Виртуальный» вызов без virtual 
a.k.a. Curiously Recurring Template Pattern 
22
«Виртуальный» вызов без virtual 
a.k.a. Curiously Recurring Template Pattern 
23 
template<typename Derived> 
class Base { 
void do() { 
Derived::do(); 
} 
};
«Виртуальный» вызов без virtual 
a.k.a. Curiously Recurring Template Pattern 
24 
template<typename Derived> 
class Base { 
void do() { 
Derived::do(); 
} 
}; 
class MyDerived : public Base<MyDerived> { 
void do() { std::cout << "my derived"; } 
};
«Виртуальный» вызов без virtual 
a.k.a. Curiously Recurring Template Pattern 
25 
template<typename Derived> 
class Base { 
void do() { 
Derived::do(); 
} 
}; 
class MyDerived : public Base<MyDerived> { 
void do() { std::cout << "my derived"; } 
}; 
Base<MyDerived>* b = new MyDerived(); 
b->do(); // my derived
«Виртуальный» вызов без virtual 
a.k.a. Curiously Recurring Template Pattern 
26 
template<typename Derived> 
class Base { 
void do() { 
static_cast<Derived*>(this)->do(); 
} 
}; 
class MyDerived : public Base<MyDerived> { 
void do() { std::cout << "my derived"; } 
}; 
Base<MyDerived>* b = new MyDerived(); 
b->do(); // my derived
27 
CRTP 
 Идеально подходит для шаблона 
проектирования «Template method» 
 «Виртуальный» метод может быть 
статическим 
 Работает в ~7 раз быстрее виртуальной 
версии
28 
Иногда без статического 
полиморфизма не 
обойтись
29 
Tag dispatching 
template <class InputIter, class Dist> 
void advance (InputIter& it, Dist n); 
template <class InputIter, class Dist> 
void advance(InputIter& i, Dist n) { 
while (n--) ++i; 
} 
template <class RndAcsIter, class Dist> 
void advance(RndAcsIter& i, Dist n) { 
i += n; 
}
30 
Tag dispatching 
template <class InputIter, class Dist> 
void advance (InputIter& it, Dist n); 
template <class InputIter, class Dist> 
void advance(InputIter& i, Dist n, input_iter_tag) { 
while (n--) ++i; 
} 
template <class RndAcsIter, class Dist> 
void advance(RndAcsIter& i, Dist n, rnd_acs_iter_tag) { 
i += n; 
}
31 
Tag dispatching 
template <class InputIter, class Dist> 
void advance (InputIter& it, Dist n) { 
typename iter_traits<InputIter>::iter_category cat; 
advance(i, n, cat); 
} 
template <class InputIter, class Dist> 
void advance(InputIter& i, Dist n, input_iter_tag) { 
while (n--) ++i; 
} 
template <class RndAcsIter, class Dist> 
void advance(RndAcsIter& i, Dist n, rnd_acs_iter_tag) { 
i += n; 
}
32 
Совмещаем концепции
33 
Задача 
 Например, мы пишем дебаггер 
 Есть множество объектов, не связанных 
какой-либо иерархией 
 Хотим сложить их в одну коллекцию, 
проитерироваться по ней, и сдампить объекты 
int x = 10; 
Foo bar; 
objects.add(x); 
objects.add(bar); 
for (const auto& obj : objects) { 
obj.dump(); 
}
34 
External polymorphism 
struct Dumpable { 
virtual void dump() const = 0; 
};
35 
External polymorphism 
struct Dumpable { 
virtual void dump() const = 0; 
}; 
template<typename T> 
class ConcreteDumpable<T> : public Dumpable { 
const T& value; 
public: 
ConcreteDumpable(const T& value) : value(value) {} 
virtual void dump() const { 
::dump(value); 
} 
};
36 
External polymorphism 
struct Dumpable { 
virtual void dump() const = 0; 
}; 
template<typename T> 
class ConcreteDumpable<T> : public Dumpable { 
const T& value; 
public: 
ConcreteDumpable(const T& value) : value(value) {} 
virtual void dump() const { 
::dump(value); 
} 
}; 
void dump(const Foo& foo) { 
foo.printToConsole(); 
}
37 
External polymorphism 
class Dumper { 
std::vector<Dumpable*> dumpables; 
public: 
template<typename T> 
void add(T& obj) { 
auto dumpable = new ConcreteDumpable<T>(obj); 
dumpables.push_back(dumpable); 
} 
void dumpAll() const { 
for (auto d : dumpables) { d->dump(); } 
} 
};
38 
External polymorphism 
class Dumper { 
std::vector<Dumpable*> dumpables; 
public: 
template<typename T> 
void add(T& obj) { 
auto dumpable = new ConcreteDumpable<T>(obj); 
dumpables.push_back(dumpable); 
} 
void dumpAll() const { 
for (auto d : dumpables) { d->dump(); } 
} 
} dumper; 
int x = 10; 
Foo bar; 
dumper.add(x); 
dumper.add(foo); 
dumper.dumpAll();
39 
External polymorphism 
 Симбиоз виртуального и статического 
полиморфизма 
 Для поддержки нового типа T надо добавить 
только ::dump(T) 
 Можно строить параллельные иерархии
40 
Новые возможности C++
Новые возможности C++11: лямбды 
41 
int x = 10; 
vector<int> v = { 1, 2, 3 }; 
for_each(v.begin(), v.end(), [x](int i){cout << i+x;});
Новые возможности C++11: лямбды 
42 
int x = 10; 
vector<int> v = { 1, 2, 3 }; 
for_each(v.begin(), v.end(), [x](int i){cout << i+x;}); 
class Lambda { 
int x; 
public: 
Lambda(int x) : x(x) {} 
void operator( )(int i) {cout << i+x;} 
}; 
for_each(Lambda());
Новые возможности C++14: лямбды 
43 
int x = 10; 
vector<int> v = { 1, 2, 3 }; 
for_each(v.begin(), v.end(), [x](auto i){cout << i+x;});
Новые возможности C++14: лямбды 
44 
int x = 10; 
vector<int> v = { 1, 2, 3 }; 
for_each(v.begin(), v.end(), [x](auto i){cout << i+x;}); 
class Lambda { 
int x; 
public: 
Lambda(int x) : x(x) {} 
template<typename T> 
void operator( )(T i) {cout << i+x;} 
};
45 
Новые возможности C++11: 
std::function 
using namespace std; 
void print(int i) { cout << i; } 
struct Print { 
void operator()(int i) {cout << i+x;} 
}
46 
Новые возможности C++11: 
std::function 
using namespace std; 
void print(int i) { cout << i; } 
struct Print { 
void operator()(int i) {cout << i+x;} 
} 
function<void(int)> p1 = print; 
function<void(int)> p1 = Print; 
function<void(int)> p1 = [](int i) {cout << i+x;};
47 
Новые возможности C++11: 
std::function 
using namespace std; 
void print(int i) { cout << i; } 
struct Print { 
void operator()(int i) {cout << i+x;} 
} 
function<void(int)> p1 = print; 
function<void(int)> p1 = Print; 
function<void(int)> p1 = [](int i) {cout << i+x;};
48 
Новые возможности C++11: 
std::function 
 Медленные (~10 раз медленнее шаблонной 
функции) 
 Обеспечивают поддержку концептов 
 Позволяют сохранить исполняемые объекты
49 
Новые возможности C++11: 
std::function 
 Медленные (~10 раз медленнее шаблонной 
функции) 
 Обеспечивают поддержку концептов 
 Позволяют сохранить исполняемые объекты 
 Не замена шаблонам и виртуальным методам!
50 
Пример из жизни
51 
Исходные условия 
id=1234 t time=2014.26.09 19:00 
struct RecordBase { 
void Load(const string& str); 
string GetValue(const string& key) const; 
void SetValue(const string& key, const string& value); 
};
52 
Версия 1.0 
struct EventRecord : RecordBase { 
int GetId() const { 
string str = GetValue("id"); 
// Parse id from str 
return id; 
} 
void SetId(int id) { 
// Serialize id to str 
SetValue("id", str); 
} 
time_t GetTs() const { 
string str = GetValue("time"); 
// Parse ts from str 
return ts; 
} 
void SetTs(time_t ts) { 
// Serialize ts to str 
SetValue("date", str); 
} 
};
53 
Версия 1.1 
struct EventRecord : RecordBase { 
int GetId() const { 
return ::FromString(GetValue("id")); 
} 
void SetId(int id) { 
SetValue("id", ::ToString(id)); 
} 
int GetTs() const { 
return ::FromString(GetValue("time")); 
} 
void SetTs(time_t ts) { 
SetValue("time", ::ToString(ts)); 
} 
};
54 
Уходим из :: 
template<typename T> 
struct Serializer { 
static T FromString(const string& str) { 
return ::FromString(str); 
} 
static string FromString(const T& value) { 
return ::ToString(value); 
} 
};
55 
Инкапсулируем логику RecordBase 
struct RecordBase { 
string GetValue(const string& key) const; 
void SetValue(const string& key, const string& value); 
template<typename Szr = Serializer, typename T> 
T Get(const string& key) const { 
return Szr::FromString(GetValue(key)); 
} 
template<typename Szr = Serializer, typename T> 
void Set(const string& key, const T& value) { 
SetValue(key, Szr::ToString(ts)); 
} 
};
56 
Упрощаем EventRecord 
struct EventRecord : RecordBase { 
int GetId() const { 
return Get<>("id"); 
} 
void SetId(int id) { 
Set<>("id", id); 
} 
int GetTs() const { 
return Get<DateSerializer>("time"); 
} 
void SetTs(time_t ts) { 
Set<DateSerializer>("time", ts); 
} 
};
57 
Еще больше инкапсуляции 
template<typename T, typename Szr = Serializer> 
class Property { 
RecordBase* record; 
string key; 
public: 
Property(RecordBase* record, const string& key) 
: record(record), key(key) {} 
T Get() const { 
return Szr::FromString(record->GetValue(key)); 
} 
void SetTs(const T& value) { 
record->SetValue(key, Szr::ToString(value)); 
} 
};
58 
Итоговая версия 
struct EventRecord : RecordBase { 
Property<int> Id; 
Property<time_t, DateSerializer> Ts; 
EventRecord() : Id("id"), Ts("time") {} 
}; 
EventRecord record; 
record.Id.Set(123); 
time_t ts = record.Ts.Get();
59 
Итоги
60 
Топ фич (субъективный) 
1. Обычный метод/функция 
2. Шаблонный метод/функция (+лямбды) 
3. Шаблонный класс (+CRTP) 
4. Виртуальный метод 
5. Внешний полиморфизм 
6. std::function
61 
Топ фич (субъективный) 
1. Обычный метод/функция 
2. Шаблонный метод/функция (+лямбды) 
3. Шаблонный класс (+CRTP) 
4. Виртуальный метод 
5. Внешний полиморфизм 
6. std::function
62 
Спасибо за внимание! 
Дмитрий Леванов 
Ведущий разработчик Крипта 
levanov@yandex-team.ru
63 
Источники 
1. http://www.inteks.ru/OOAD/P-Cources.OOAD.part1.pdf 
2. http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern 
3. http://www.cs.wustl.edu/~schmidt/PDF/External-Polymorphism.pdf 
4. http://www.generic-programming.org/languages/cpp/techniques.php 
5. http://eli.thegreenplace.net/2013/12/05/the-cost-of-dynamic-virtual-calls- 
vs-static-crtp-dispatch-in-c/

Статический и динамический полиморфизм в C++, Дмитрий Леванов

  • 1.
  • 2.
    2 Статический и динамический полиморфизм в C++ Дмитрий Леванов Ведущий разработчик Крипта
  • 3.
    3 Крипта Отвечает на вопрос «Кто?»  Определяет интересы по поведению в интернете  Используется для таргетинга рекламы  От др.-греч. κρυπτή — крытый подземный ход, тайник
  • 4.
    4 Как училиКрипту + Логи Обучение Контроль Матрикснет
  • 5.
  • 6.
    6 Разработка Крипты  Много логов в разных форматах  Сложные цепочки обработки  Высокие требования к производительности  Много одинаковой похожей логики  Хочется делать всё однообразно
  • 7.
  • 8.
    8 Полиморфизм Способ поставить в соответствие некой грамматической конструкции контекстно- зависимую семантику или, по-русски:  Текст программы [почти] один и тот же, а смысл разный
  • 9.
    9 Виртуальный полиморфизм struct Base { virtual void do() { std::cout << “base”; } }; struct Derived : public Base { virtual void do() { std::cout << “derived”; } }; Base* b = new Derived(); b->do(); // derived  ООП-шненько  Типобезопасно  Работают фичи, зависящие от _vptr
  • 10.
    Виртуальный полиморфизм: минусы  Медленный вызов методов  Надо поддерживать иерархию классов  Приходится иметь дело с T* или T&  Грабли с виртуальными методами  Статический метод не может быть виртуальным  Инвариантность параметров 10
  • 11.
    11 Зачастую всесводится к… void for_each(const vector<int>& v, const Handler& h) { for (int i : v) { h.handle(i); } } //... vector<int> vect = {1,2,3}; MyHandler handler; for_each(vect, handler);
  • 12.
    12 То жесамое, но лучше template<typename Handler> void for_each(const vector<int>& v, const Handler& h) { for (int i : v) { h.handle(i); } } //... vector<int> vect = {1,2,3}; MyHandler handler; for_each(vect, handler);
  • 13.
    13 Продолжаем улучшать template<typename Handler> void for_each(const vector<int>& v, const Handler& h) { for (int i : v) { h(i); } } //... vector<int> vect = {1,2,3}; MyHandler handler; for_each(vect, handler);
  • 14.
    14 Совсем хорошо template<typename Handler> void for_each(const vector<int>& v, const Handler& h) { for (int i : v) { h(i); } } //... vector<int> vect = {1,2,3}; for_each(vect, [](int i){ cout << i; });
  • 15.
    15 Или так template<typename Handler> void for_each(const vector<int>& v) { for (int i : v) { Handler::handle(i); } } //... vector<int> vect = {1,2,3}; MyHandler handler; for_each<MyHandler>(vect);
  • 16.
    16 Статический полиморфизм:плюсы  Типобезопасно  Быстрый вызов методов  Не надо наследоваться  Не надо иметь дело с указателями  Контрвариантность параметров  Можно использовать лямбды
  • 17.
    Статический полиморфизм: минусы 17  Нельзя положить в коллекцию  Сложно проверять правильность кода  Медленно компилируется  Может распухнуть бинарник  Нет поддержки концептов  Есть ограничения компилятора  Не во всех IDE правильно работает автокомплит
  • 18.
    18 Синтаксис иногдадовольно странный… this->do();
  • 19.
    19 Синтаксис иногдадовольно странный… this->do(); typename T::iter f(typename T::iter i);
  • 20.
    20 Синтаксис иногдадовольно странный… this->do(); typename T::iter f(typename T::iter i); this->template do<T>(); // WTF???
  • 21.
    21 Замещение виртуального полиморфизма статическим
  • 22.
    «Виртуальный» вызов безvirtual a.k.a. Curiously Recurring Template Pattern 22
  • 23.
    «Виртуальный» вызов безvirtual a.k.a. Curiously Recurring Template Pattern 23 template<typename Derived> class Base { void do() { Derived::do(); } };
  • 24.
    «Виртуальный» вызов безvirtual a.k.a. Curiously Recurring Template Pattern 24 template<typename Derived> class Base { void do() { Derived::do(); } }; class MyDerived : public Base<MyDerived> { void do() { std::cout << "my derived"; } };
  • 25.
    «Виртуальный» вызов безvirtual a.k.a. Curiously Recurring Template Pattern 25 template<typename Derived> class Base { void do() { Derived::do(); } }; class MyDerived : public Base<MyDerived> { void do() { std::cout << "my derived"; } }; Base<MyDerived>* b = new MyDerived(); b->do(); // my derived
  • 26.
    «Виртуальный» вызов безvirtual a.k.a. Curiously Recurring Template Pattern 26 template<typename Derived> class Base { void do() { static_cast<Derived*>(this)->do(); } }; class MyDerived : public Base<MyDerived> { void do() { std::cout << "my derived"; } }; Base<MyDerived>* b = new MyDerived(); b->do(); // my derived
  • 27.
    27 CRTP Идеально подходит для шаблона проектирования «Template method»  «Виртуальный» метод может быть статическим  Работает в ~7 раз быстрее виртуальной версии
  • 28.
    28 Иногда безстатического полиморфизма не обойтись
  • 29.
    29 Tag dispatching template <class InputIter, class Dist> void advance (InputIter& it, Dist n); template <class InputIter, class Dist> void advance(InputIter& i, Dist n) { while (n--) ++i; } template <class RndAcsIter, class Dist> void advance(RndAcsIter& i, Dist n) { i += n; }
  • 30.
    30 Tag dispatching template <class InputIter, class Dist> void advance (InputIter& it, Dist n); template <class InputIter, class Dist> void advance(InputIter& i, Dist n, input_iter_tag) { while (n--) ++i; } template <class RndAcsIter, class Dist> void advance(RndAcsIter& i, Dist n, rnd_acs_iter_tag) { i += n; }
  • 31.
    31 Tag dispatching template <class InputIter, class Dist> void advance (InputIter& it, Dist n) { typename iter_traits<InputIter>::iter_category cat; advance(i, n, cat); } template <class InputIter, class Dist> void advance(InputIter& i, Dist n, input_iter_tag) { while (n--) ++i; } template <class RndAcsIter, class Dist> void advance(RndAcsIter& i, Dist n, rnd_acs_iter_tag) { i += n; }
  • 32.
  • 33.
    33 Задача Например, мы пишем дебаггер  Есть множество объектов, не связанных какой-либо иерархией  Хотим сложить их в одну коллекцию, проитерироваться по ней, и сдампить объекты int x = 10; Foo bar; objects.add(x); objects.add(bar); for (const auto& obj : objects) { obj.dump(); }
  • 34.
    34 External polymorphism struct Dumpable { virtual void dump() const = 0; };
  • 35.
    35 External polymorphism struct Dumpable { virtual void dump() const = 0; }; template<typename T> class ConcreteDumpable<T> : public Dumpable { const T& value; public: ConcreteDumpable(const T& value) : value(value) {} virtual void dump() const { ::dump(value); } };
  • 36.
    36 External polymorphism struct Dumpable { virtual void dump() const = 0; }; template<typename T> class ConcreteDumpable<T> : public Dumpable { const T& value; public: ConcreteDumpable(const T& value) : value(value) {} virtual void dump() const { ::dump(value); } }; void dump(const Foo& foo) { foo.printToConsole(); }
  • 37.
    37 External polymorphism class Dumper { std::vector<Dumpable*> dumpables; public: template<typename T> void add(T& obj) { auto dumpable = new ConcreteDumpable<T>(obj); dumpables.push_back(dumpable); } void dumpAll() const { for (auto d : dumpables) { d->dump(); } } };
  • 38.
    38 External polymorphism class Dumper { std::vector<Dumpable*> dumpables; public: template<typename T> void add(T& obj) { auto dumpable = new ConcreteDumpable<T>(obj); dumpables.push_back(dumpable); } void dumpAll() const { for (auto d : dumpables) { d->dump(); } } } dumper; int x = 10; Foo bar; dumper.add(x); dumper.add(foo); dumper.dumpAll();
  • 39.
    39 External polymorphism  Симбиоз виртуального и статического полиморфизма  Для поддержки нового типа T надо добавить только ::dump(T)  Можно строить параллельные иерархии
  • 40.
  • 41.
    Новые возможности C++11:лямбды 41 int x = 10; vector<int> v = { 1, 2, 3 }; for_each(v.begin(), v.end(), [x](int i){cout << i+x;});
  • 42.
    Новые возможности C++11:лямбды 42 int x = 10; vector<int> v = { 1, 2, 3 }; for_each(v.begin(), v.end(), [x](int i){cout << i+x;}); class Lambda { int x; public: Lambda(int x) : x(x) {} void operator( )(int i) {cout << i+x;} }; for_each(Lambda());
  • 43.
    Новые возможности C++14:лямбды 43 int x = 10; vector<int> v = { 1, 2, 3 }; for_each(v.begin(), v.end(), [x](auto i){cout << i+x;});
  • 44.
    Новые возможности C++14:лямбды 44 int x = 10; vector<int> v = { 1, 2, 3 }; for_each(v.begin(), v.end(), [x](auto i){cout << i+x;}); class Lambda { int x; public: Lambda(int x) : x(x) {} template<typename T> void operator( )(T i) {cout << i+x;} };
  • 45.
    45 Новые возможностиC++11: std::function using namespace std; void print(int i) { cout << i; } struct Print { void operator()(int i) {cout << i+x;} }
  • 46.
    46 Новые возможностиC++11: std::function using namespace std; void print(int i) { cout << i; } struct Print { void operator()(int i) {cout << i+x;} } function<void(int)> p1 = print; function<void(int)> p1 = Print; function<void(int)> p1 = [](int i) {cout << i+x;};
  • 47.
    47 Новые возможностиC++11: std::function using namespace std; void print(int i) { cout << i; } struct Print { void operator()(int i) {cout << i+x;} } function<void(int)> p1 = print; function<void(int)> p1 = Print; function<void(int)> p1 = [](int i) {cout << i+x;};
  • 48.
    48 Новые возможностиC++11: std::function  Медленные (~10 раз медленнее шаблонной функции)  Обеспечивают поддержку концептов  Позволяют сохранить исполняемые объекты
  • 49.
    49 Новые возможностиC++11: std::function  Медленные (~10 раз медленнее шаблонной функции)  Обеспечивают поддержку концептов  Позволяют сохранить исполняемые объекты  Не замена шаблонам и виртуальным методам!
  • 50.
  • 51.
    51 Исходные условия id=1234 t time=2014.26.09 19:00 struct RecordBase { void Load(const string& str); string GetValue(const string& key) const; void SetValue(const string& key, const string& value); };
  • 52.
    52 Версия 1.0 struct EventRecord : RecordBase { int GetId() const { string str = GetValue("id"); // Parse id from str return id; } void SetId(int id) { // Serialize id to str SetValue("id", str); } time_t GetTs() const { string str = GetValue("time"); // Parse ts from str return ts; } void SetTs(time_t ts) { // Serialize ts to str SetValue("date", str); } };
  • 53.
    53 Версия 1.1 struct EventRecord : RecordBase { int GetId() const { return ::FromString(GetValue("id")); } void SetId(int id) { SetValue("id", ::ToString(id)); } int GetTs() const { return ::FromString(GetValue("time")); } void SetTs(time_t ts) { SetValue("time", ::ToString(ts)); } };
  • 54.
    54 Уходим из:: template<typename T> struct Serializer { static T FromString(const string& str) { return ::FromString(str); } static string FromString(const T& value) { return ::ToString(value); } };
  • 55.
    55 Инкапсулируем логикуRecordBase struct RecordBase { string GetValue(const string& key) const; void SetValue(const string& key, const string& value); template<typename Szr = Serializer, typename T> T Get(const string& key) const { return Szr::FromString(GetValue(key)); } template<typename Szr = Serializer, typename T> void Set(const string& key, const T& value) { SetValue(key, Szr::ToString(ts)); } };
  • 56.
    56 Упрощаем EventRecord struct EventRecord : RecordBase { int GetId() const { return Get<>("id"); } void SetId(int id) { Set<>("id", id); } int GetTs() const { return Get<DateSerializer>("time"); } void SetTs(time_t ts) { Set<DateSerializer>("time", ts); } };
  • 57.
    57 Еще большеинкапсуляции template<typename T, typename Szr = Serializer> class Property { RecordBase* record; string key; public: Property(RecordBase* record, const string& key) : record(record), key(key) {} T Get() const { return Szr::FromString(record->GetValue(key)); } void SetTs(const T& value) { record->SetValue(key, Szr::ToString(value)); } };
  • 58.
    58 Итоговая версия struct EventRecord : RecordBase { Property<int> Id; Property<time_t, DateSerializer> Ts; EventRecord() : Id("id"), Ts("time") {} }; EventRecord record; record.Id.Set(123); time_t ts = record.Ts.Get();
  • 59.
  • 60.
    60 Топ фич(субъективный) 1. Обычный метод/функция 2. Шаблонный метод/функция (+лямбды) 3. Шаблонный класс (+CRTP) 4. Виртуальный метод 5. Внешний полиморфизм 6. std::function
  • 61.
    61 Топ фич(субъективный) 1. Обычный метод/функция 2. Шаблонный метод/функция (+лямбды) 3. Шаблонный класс (+CRTP) 4. Виртуальный метод 5. Внешний полиморфизм 6. std::function
  • 62.
    62 Спасибо завнимание! Дмитрий Леванов Ведущий разработчик Крипта levanov@yandex-team.ru
  • 63.
    63 Источники 1.http://www.inteks.ru/OOAD/P-Cources.OOAD.part1.pdf 2. http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern 3. http://www.cs.wustl.edu/~schmidt/PDF/External-Polymorphism.pdf 4. http://www.generic-programming.org/languages/cpp/techniques.php 5. http://eli.thegreenplace.net/2013/12/05/the-cost-of-dynamic-virtual-calls- vs-static-crtp-dispatch-in-c/