3
Крипта
Отвечает на вопрос «Кто?»Определяет интересы по поведению в
интернетеИспользуется для таргетинга рекламыОт др.-греч. κρυπτή — крытый подземный
ход, тайник
6
Разработка Крипты
Много логов в разных форматахСложные цепочки обработкиВысокие требования к производительности
Много одинаковой похожей логикиХочется делать всё однообразно
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
10
Виртуальный полиморфизм: минусы
Медленный вызов методовНадо поддерживать иерархию классовПриходится иметь дело с T* или T&Грабли с виртуальными методамиСтатический метод не может быть
виртуальнымИнвариантность параметров
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 правильно работает
автокомплит
20
Синтаксис иногда довольно странный…
this->do();
typename T::iter f(typename T::iter i);
this->template do<T>(); // WTF???
23
«Виртуальный» вызов без virtuala.k.a. Curiously Recurring Template Pattern
template<typename Derived>class Base { void do() { Derived::do(); }};
24
«Виртуальный» вызов без virtuala.k.a. Curiously Recurring Template Pattern
template<typename Derived>class Base { void do() { Derived::do(); }};
class MyDerived : public Base<MyDerived> { void do() { std::cout << "my derived"; }};
25
«Виртуальный» вызов без virtuala.k.a. Curiously Recurring Template Pattern
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
«Виртуальный» вызов без virtuala.k.a. Curiously Recurring Template Pattern
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 раз быстрее виртуальной версии
29
Tag dispatchingtemplate <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 dispatchingtemplate <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 dispatchingtemplate <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;}
33
ЗадачаНапример, мы пишем дебаггерЕсть множество объектов, не связанных
какой-либо иерархиейХотим сложить их в одну коллекцию,
проитерироваться по ней, и сдампить объекты
int x = 10;Foo bar;objects.add(x);objects.add(bar);
for (const auto& obj : objects) { obj.dump();}
35
External polymorphismstruct 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 polymorphismstruct 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 polymorphismclass 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 polymorphismclass 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)
Можно строить параллельные иерархии
41
Новые возможности C++11: лямбдыint x = 10;vector<int> v = { 1, 2, 3 };
for_each(v.begin(), v.end(), [x](int i){cout << i+x;});
42
Новые возможности C++11: лямбды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: лямбдыint x = 10;vector<int> v = { 1, 2, 3 };
for_each(v.begin(), v.end(), [x](auto i){cout << i+x;});
44
Новые возможности C++14: лямбды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 раз медленнее шаблонной функции)
Обеспечивают поддержку концептовПозволяют сохранить исполняемые объекты
Не замена шаблонам и виртуальным методам!
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.0struct 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.1struct 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
Упрощаем EventRecordstruct 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();
60
Топ фич (субъективный)
1. Обычный метод/функция2. Шаблонный метод/функция (+лямбды)3. Шаблонный класс (+CRTP)4. Виртуальный метод5. Внешний полиморфизм6. std::function
61
Топ фич (субъективный)
1. Обычный метод/функция2. Шаблонный метод/функция (+лямбды)3. Шаблонный класс (+CRTP)4. Виртуальный метод5. Внешний полиморфизм6. std::function
63
Источники
1. http://www.inteks.ru/OOAD/P-Cources.OOAD.part1.pdf2. http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern3. http://www.cs.wustl.edu/~schmidt/PDF/External-Polymorphism.pdf4. http://www.generic-programming.org/languages/cpp/techniques.php5. http://eli.thegreenplace.net/2013/12/05/the-cost-of-dynamic-virtual-call
s-vs-static-crtp-dispatch-in-c/