C++ templates
Синтаксис template void f(const T& value) { std::cout
Примеры использования template class auto_ptr { typedef auto_ptr MyType; T* _ptr; auto_ptr(const MyType& other); MyType& operator = (const MyType& other); public: auto_ptr(T* const ptr) : _ptr(ptr) { } ~auto_ptr() { delete _ptr; } T& operator *() const { return *_ptr; } T* operator ->() const { return _ptr; } };
Примеры использования struct A { int a; }; int main() { auto_ptr p_a = new A; (*p_a).a = 9; int i = p_a->a; return 0; }
smart pointers std::auto_ptr – лучше не использовать _com_ptr_t – для COM-интерфейсов boost::scoped_ptr – некопируемый boost::shared_ptr – копируемый, использует подсчёт ссылок boost::weak_ptr – решает проблему «кольцевых ссылок»
boost:: scoped_ptr template class scoped_ptr // noncopyable { T * ptr; scoped_ptr(scoped_ptr const &); // prohibited scoped_ptr & operator=(scoped_ptr const &); // prohibited void operator==( scoped_ptr const& ) const; // prohibited void operator!=( scoped_ptr const& ) const; // prohibited public: explicit scoped_ptr(T * p = 0); // never throws explicit scoped_ptr(std::auto_ptr p); // never throws ~scoped_ptr(); // never throws T & operator*() const; // never throws T * operator->() const; // never throws operator bool () const; // never throws bool operator! () const; // never throws T * get() const; // never throws void reset(T * p = 0); // never throws void swap(scoped_ptr & b); // never throws };
std::auto_ptr template class auto_ptr { public: template operator auto_ptr () { return (auto_ptr (*this)); } template auto_ptr & operator = (auto_ptr & _Right) { reset(_Right.release()); return (*this); } template auto_ptr(auto_ptr & _Right) : _Myptr(_Right.release()) {} _Ty *release() { _Ty *_Tmp = (_Ty *)_Myptr; _Myptr = 0; return (_Tmp); }... };
Недостатки глобальных переменных Объекты создаются всегда, даже если они не используются Порядок инициализации в общем случае неизвестен Объекты не разрушаются до завершения программы Проблемы с исключениями в конструкторах объектов
Singleton template class Singleton { public: static T& Instance() { static T instance; return instance; } static const T& ConstInstance() { return const_cast (Instance()); } };
Singleton class A { private: friend class Singleton ; A() {} public: int a; }; int main() { Singleton ::Instance().a = 3; std::cout ::ConstInstance().a
Частичная специализация шаблонов template T MaxValue(); template int MaxValue () { return INT_MAX; } template float MaxValue () { return FLT_MAX; } int main() { std::cout ()
Compile time check template struct CompileTimeError; template struct CompileTimeError {}; CompileTimeError ERROR_assert_failed; #define STATIC_CHECK(expr, msg) \ { CompileTimeError ERROR_##msg; (void)ERROR_##msg; } int main() { STATIC_CHECK(2 == 5, assert_failed) return 0; }
Шаблонные шаблонные параметры template class Creator = NewCreator > class Singleton { public: typedef T* InstancePtr; private: static InstancePtr _instancePtr; static void Destroy(void) { if(_instancePtr != NULL) Creator ::Destroy(_instancePtr); } public: static T& Instance() { if(_instancePtr == NULL) { _instancePtr = Creator ::Create(); atexit(&Singleton::Destroy); } return *_instancePtr; } }; template class C> typename Singleton ::InstancePtr Singleton ::_instancePtr = NULL;
Шаблонные шаблонные параметры template struct MallocCreator { static T* Create() { void* p = std::malloc(sizeof(T)); if (!p) return 0; return new(p) T; } static void Destroy(T* p) { p->~T(); std::free(p); } }; template struct NewCreator { static T* Create() { return new T; } static void Destroy(T* p) { delete p; } };
Недостатки указателей на функции Нет информации о типах аргументов и возвращаемого значения Указатель на функцию необходимо перед вызовом проверять на NULL Есть возможность привести указатель на функцию к любому указателю Разный синтаксис вызова для указателей на функции и указателей на методы
Функторы, простая реализация template class function; template class function { typedef function MyType; typedef R (*Signature)(P); Signature _func; MyType& operator = (const MyType&); public: function(Signature func) : _func(func) { } function(const MyType& other): _func(other._func) { } R operator () (P p) { return _func(p); } };
Функторы, простая реализация template class function { typedef function MyType; typedef R (ObjType::*Signature)(P1, P2); Signature _func; MyType& operator = (const MyType&); public: function(Signature func) : _func(func) { } function(const MyType& other): _func(other._func) { } R operator () (ObjType& obj, P1 p1, P2 p2) { return (obj.*_func)(p1, p2); } };
Функторы, простая реализация struct A { char C; A(char c = X') : C(c) { } void member_func(double i, bool b) { if (b) std::cout
Функторы STL int main() { A a; std::mem_fun1_t f = std::mem_fun(&A::member_func); f(&a, 0.5); std::mem_fun1_ref_t f_ref = std::mem_fun_ref(&A::member_func); f_ref(a, 0.7); std::pointer_to_unary_function f2 = std::ptr_fun(&abs); std::cout
Недостатки функторов STL Уродливый синтаксис Отсутствие функторов с большим количеством параметров Отсутствует возможность инициализации функтора с сигнатурой func1 указателем на func2: struct B : public A{}; void func1(B*); void func2(A*);
boost::function int main() { A a; boost::function f = &A::member_func; f(a, 0.5); boost::function f2 = &abs; std::cout
Применение функторов void generate_int(int& i) { i = rand() % ; } void print_int(int i) { std::cout
Привязывание параметров int main() { std::vector vec(10); std::for_each(vec.begin(), vec.end(), &generate_int); std::for_each(vec.begin(), vec.end(), &print_int); std::cout
Недостатки std::bind1st/2nd Работают только для binary_function Привязывают только один аргумент Неудобный синтаксис Нет возможности привязать ссылку: void inc (int& n, bool) { ++n; } //... std::bind1st(std::ptr_fun(&inc), i) (true);
boost::bind bool in_range( int min_val, int max_val, int val ) { return (val >= min_val) && (val
Подводные камни boost::bind class WindowBase { typedef boost::function EventHandler; EventHandler _onPaint; protected: WindowBase(const EventHandler& onPaint) : _onPaint(onPaint) { } //... }; struct MyWindow : public WindowBase { MyWindow() : WindowBase(boost::bind(&MyWindow::OnPaint, this)) { } void OnPaint() { } }; MyWindow CreateMyGreatWindow() { return MyWindow(); } int main() { MyWindow wnd = CreateMyGreatWindow(); return 0; }
Преимущества использования шаблонов C++ Шаблоны решают проблему дублирования кода Зачастую шаблоны позволяют избавиться от динамической диспечеризации и повысить скорость работы приложения Позволяют отследить большую часть ошибок на этапе компиляции Использование стратегий позволяет не писать сложные классы с нуля, а собирать их из множества меньших Можно грабить корованы
Список литературы Бьерн Страуструп. Язык программирования С++ Скотт Мейерс. Эффективное использование С++ Скотт Мейерс. Наиболее эффективное использование С++ Скотт Мейерс. Эффективное использование STL Герб Саттер. Решение сложных задач на C++ Герб Саттер. Новые сложные задачи на C++ Андрей Александреску. Современное проектирование на C++ Герб Саттер. Андрей Александреску. Стандарты программирования на С правило и рекомендация Владимир Сорокин. Голубое сало.