Slide 1

Slide 1 text

ОБЪЕКТНО- ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ Лекция № 2 / 4
 25.09.2018 г.

Slide 2

Slide 2 text

ОБЪЯВЛЕНИЕ ПСЕВДОНИМА (ALIAS DECLARATION) std::unique_ptr> ptr; // typedef specifier typedef std::unique_ptr> UPtrMapSS; // alias declaration using UPtrMapSS = std::unique_ptr>;

Slide 3

Slide 3 text

ПРЕИМУЩЕСТВА ПСЕВДОНИМОВ • Более простое для восприятия при работе с типами, включающие указатели на функции. • Объявления псевдонимов могут быть шаблонизированы.

Slide 4

Slide 4 text

// FP является синонимом для указателя на функцию, // принимающую int и const std::string& и ничего не // возвращающую typedef void (*FP) (int, const std::string&); // То же самое, но как объявление псевдонима using FP = void (*) (int, const std::string&);

Slide 5

Slide 5 text

ШАБЛОНЫ ПСЕВДОНИМОВ // MyAlloc - пользовательский распределитель // памяти. template struct MyAllocList { typedef std::list> type; }; MyAllocList::type lw; // Клиентский // код // Все хуже, когда MyAllocList используется // как член-данные template struct Widget { private: //MyAllocList::type - dependent type typename MyAllocList::type list; }; template using MyAllocList = std::list>; //Убирается суффикс "::type" MyAllocList lw; // Клиентский // код template struct Widget { private: //Ни typename, ни ::type MyAllocList list; };

Slide 6

Slide 6 text

#include std::remove_const::type //C++11 : const Т -> Т std::remove_reference::type //C++11 : Т& / Т&& -> Т std::add_lvalue_reference::type //C++11 : Т -> Т& template using remove_const_t = typename std::remove_const::type; template using remove_reference_t = typename std::remove_reference::type; template using add_lvalue_reference_t = typename std::add_lvalue_reference::type; std::remove_const_t //C++14 : const Т -> Т std::remove_reference_t //C++14 : Т& / Т&& -> Т std::add_lvalue_reference_t //C++14 : Т -> Т&

Slide 7

Slide 7 text

DECLTYPE const int i = 0; // decltype(i) - const int bool f (const Widget &w); // decltype(w) - const Widget& // decltype(f) - bool (const Widget&) struct Point{ int x, y; // decltype(Point::x) - int }; // decltype(Point::y) - int template class vector{ public: ... T& operator[](size_t index); } vector v; // decltype(v) - vector if(v[0] == 0) ... // decltype(v[0]) - int&

Slide 8

Slide 8 text

// C++11 - завершающий возвращаемый тип template auto authAndAccess(Container &c, Index i) -> decltype(c[i]) { authenticateUser(); return c[i]; //Возвращаемый тип - ??? } // C++14 - вывод типа шаблона template auto authAndAccess(Container &c, Index i) { authenticateUser(); return c[i]; //Возвращаемый тип - ??? } ПРИМЕНЕНИЕ DELCTYPE

Slide 9

Slide 9 text

// C++11 - завершающий возвращаемый тип template auto authAndAccess(Container &c, Index i) -> decltype(c[i]) { authenticateUser(); return c[i]; //Возвращаемый тип - T& } // C++14 - вывод типа шаблона template auto authAndAccess(Container &c, Index i) { authenticateUser(); return c[i]; //Возвращаемый тип - T } ПРИМЕНЕНИЕ DELCTYPE

Slide 10

Slide 10 text

// C++14 - вывод типа шаблона template auto authAndAccess(Container &c, Index i) { authenticateUser(); return c[i]; //Возвращаемый тип - T } std::deque d; ... authAndAccess(d, 5) = 10; //Ошибка компиляции! // Решение // C++14 - вывод типа используя правила decltype template decltype(auto) authAndAccess(Container &c, Index i) { authenticateUser(); return c[i]; //Возвращаемый тип - T& } ПРИМЕНЕНИЕ DELCTYPE

Slide 11

Slide 11 text

int a = 0; const int& cref = a; auto val1 = cref; //Вывод типа auto - int decltype(auto) val2 = cref; //Вывод типа decltype - const int& ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ

Slide 12

Slide 12 text

ОСОБЕННОСТИ DECLTYPE • Для lvаluе-выражений типа T, отличных от имени, decltype всегда дает тип Т&. decltype(auto) f1(){
 int x = 0; ... return x; //decltype(x) -> int } decltype(auto) f2(){
 int x = 0; ... return (x); //decltype((x)) -> int& }

Slide 13

Slide 13 text

STD::MOVE //C++11 template typename remove_reference::type&& move(T&& param) { using ReturnType = typename remove_reference::type&&; return static_cast(param); } //C++14 template decltype(auto) move(T&& param) { using ReturnType = remove_reference_t&&; return static_cast(param); }

Slide 14

Slide 14 text

STD::FORWARD void process(const Widget& lvalArg); void process(Widget&& rvalArg); template void logAndProcess(T&& param) { auto now = std::chrono::system_clock::now(); makeLogEntry("Вызов process", now); process(std::forward(param)); } Widget w; ... logAndProcess(w); //Вызов с lvalue logAndProcess(std::move(w)); //Вызов с rvalue «Условное приведение»

Slide 15

Slide 15 text

• std::move выполняет безусловное приведение к rvalue. Сама по себе эта функция не перемещает ничего. • std::forward приводит свой аргумент к rvalue только тогда, когда этот аргумент связан с rvalue. • Ни std::move, ни std::forward не выполняют никаких действий времени выполнения. ИТАК, STD::MOVE И STD::FORWARD

Slide 16

Slide 16 text

ОТЛИЧИЕ УНИВЕРСАЛЬНЫХ ССЫЛОК ОТ RVALUE-ССЫЛОК void f(Widget &¶m); // rvalue-ссылка Widget&& var1 = Widget(); // rvalue-ссылка auto&& var2 = var1; // универсальная ссылка template void f(std::vector&& param); // rvalue-ссылка template void f(T&& param); // универсальная ссылка template void f(const T&& param); // rvalue-ссылка

Slide 17

Slide 17 text

УСЛОВИЯ ДЛЯ УНИВЕРСАЛЬНЫХ ССЫЛОК • Наличие вывода типа. • Вид объявления ссылки должен быть "T&&". template > class vector { public: // ... void push_back(T&& x); // rvalue-ссылка // ... };

Slide 18

Slide 18 text

• Если параметр шаблона функции имеет тип T&& для выводимого типа Т или если объект объявлен с использованием auto&&, то параметр или объект является универсальной ссылкой. • Если вид объявления типа не является в точности type&& или если вывод типа не имеет места, то tуре&& означает rvalue- ccылкy. • Универсальные ссылки соответствуют rvаluе-ссылкам, если они инициализируются значениями rvalue. Они соответствуют lvаluе- ссылкам, если они инициализируются значениями lvalue. СЛЕДУЕТ ЗАПОМНИТЬ

Slide 19

Slide 19 text

Widget makeWidget(){ Widget w; ... return w; } Widget makeWidget(){ Widget w; ... return std::move(w); } Никогда не применяйте std::move и std::forward к локальным объектам, которые могут быть объектом оптимизации возвращаемого значения. Так делать плохо! RVO не работает.

Slide 20

Slide 20 text

СВЕРТЫВАНИЕ ССЫЛОК (REFERENCE COLLAPSING) template void f(T&& param); // универсальная ссылка Widget widgetFactory(); // Функция, возвращающая rvalue Widget w; // Переменная lvalue f(w); // Вызов функции с lvalue; // тип T - ??? f(widgetFactory()); // Вызов функции с rvalue; // тип T - ???

Slide 21

Slide 21 text

СВЕРТЫВАНИЕ ССЫЛОК (REFERENCE COLLAPSING) template void f(T&& param); // универсальная ссылка Widget widgetFactory(); // Функция, возвращающая rvalue Widget w; // Переменная lvalue f(w); // Вызов функции с lvalue; // тип T - Widget& f(widgetFactory()); // Вызов функции с rvalue; // тип T - Widget

Slide 22

Slide 22 text

СВЕРТЫВАНИЕ ССЫЛОК (REFERENCE COLLAPSING) int x; ... auto& & rx = x; //Ошибка! Объявлять ссылки на ссылки нельзя. template void f(T&& param); Widget w; f(w); // T -> Widget& void f(Widget& && param); void f(Widget& param); How???

Slide 23

Slide 23 text

ПРАВИЛА СВЕРТЫВАНИЯ ССЫЛОК T& & T& T& && T& T&& & T& T&& && T&&

Slide 24

Slide 24 text

STD::FORWARD template void f(T&& param){ ... someFunc(std::forward(param)); } template T&& forward(remove_reference_t& param){ return static_cast(param); } Widget w; // Переменная lvalue f(w); // Вызов функции с lvalue; // тип T - Widget& f(widgetFactory()); // Вызов функции с rvalue; // тип T - Widget

Slide 25

Slide 25 text

ВЫЗОВ STD::FORWARD С LVALUE template Widget& && forward(remove_reference_t& param){ return static_cast(param); } template Widget& && forward(Widget& param){ return static_cast(param); } template Widget& forward(Widget& param){ return static_cast(param); }

Slide 26

Slide 26 text

ВЫЗОВ STD::FORWARD С RVALUE template Widget&& forward(remove_reference_t& param){ return static_cast(param); } template Widget&& forward(Widget& param){ return static_cast(param); }

Slide 27

Slide 27 text

1. ИНСТАНЦИРОВАНИЕ ШАБЛОНА template void f(T&& param); // универсальная ссылка Widget widgetFactory(); // Функция, возвращающая rvalue Widget w; // Переменная lvalue f(w); // Вызов функции с lvalue; // тип T - Widget& f(widgetFactory()); // Вызов функции с rvalue; // тип T - Widget

Slide 28

Slide 28 text

2. ГЕНЕРАЦИЯ ТИПОВ ДЛЯ ПЕРЕМЕННЫХ AUTO Widget widgetFactory(); // Функция, возвращающая rvalue Widget w; // Переменная lvalue auto&& w1 = w; auto&& w2 = widgetFactory(); Widget& && w1 = w; Widget& w1 = w; Widget&& w2 = widgetFactory();

Slide 29

Slide 29 text

3. ГЕНЕРАЦИЯ И ИСПОЛЬЗОВАНИЕ TYPEDEF И ОБЪЯВЛЕНИЙ ПСЕВДОНИМОВ template class Widget{ public: typedef T&& RvalueRefToT; }; Widget w; typedef int& && RvalueRefToT; typedef int& RvalueRefToT;

Slide 30

Slide 30 text

4. ИСПОЛЬЗОВАНИЕ DECLTYPE auto func(int& param) -> const decltype(param)&;

Slide 31

Slide 31 text

ПРЯМАЯ ПЕРЕДАЧА (PERFECT FORWARDING) struct X{ X(const int&, int&){} }; struct W{ W(int&, int&){} }; struct Y{ Y(int&, const int&){} }; struct Z{ Z(const int&, const int&){} }; template T* factory(A1& a1, A2& a2){ return new T(a1, a2); } int a = 4, b = 5; W* pw = factory(a,b); // Ok. X* pw = factory(2,b); // Error. Y* pw = factory(a,2); // Error. Z* pw = factory(2,2); // Error.

Slide 32

Slide 32 text

ПРЯМАЯ ПЕРЕДАЧА (PERFECT FORWARDING) struct X{ X(const int&, int&){} }; struct W{ W(int&, int&){} }; struct Y{ Y(int&, const int&){} }; struct Z{ Z(const int&, const int&){} }; template T* factory(A1&& a1, A2&& a2){ return new T(std::forward(a1), std::forward(a2)); } int a = 4, b = 5; W* pw = factory(a,b); // Ok. X* pw = factory(2,b); // Ok. Y* pw = factory(a,2); // Ok. Z* pw = factory(2,2); // Ok.

Slide 33

Slide 33 text

ПРЯМАЯ ПЕРЕДАЧА (PERFECT FORWARDING) template void fwd(T&& param){ f(std::forward(param)); } // Variadic template template void fwd(Ts&&... params){ f(std::forward(params)...); }