C++ templates

28
C++ templates

description

C++ templates. Синтаксис. template < typename T > void f( const T& value) { std:: cout

Transcript of C++ templates

Page 1: C++ templates

C++ templates

Page 2: C++ templates

Синтаксисtemplate < typename T > void f(const T& value) {

std::cout << "Value is: " << value << std::endl;}

template < typename T, size_t n >struct Array{

T data[n];};

Page 3: C++ templates

Примеры использованияtemplate < typename T >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; }

};

Page 4: C++ templates

Примеры использованияstruct A{

int a;};

int main(){

auto_ptr<A> p_a = new A; (*p_a).a = 9; int i = p_a->a;

return 0;}

Page 5: C++ templates

smart pointers

• std::auto_ptr – лучше не использовать

• _com_ptr_t – для COM-интерфейсов

• boost::scoped_ptr – некопируемый• boost::shared_ptr – копируемый, использует подсчёт

ссылок• boost::weak_ptr – решает проблему «кольцевых ссылок»

Page 6: C++ templates

boost:: scoped_ptrtemplate<class T> 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; // prohibitedvoid operator!=( scoped_ptr const& ) const; // prohibited

public:explicit scoped_ptr(T * p = 0); // never throwsexplicit scoped_ptr(std::auto_ptr<T> p); // never throws~scoped_ptr(); // never throws

T & operator*() const; // never throwsT * operator->() const; // never throwsoperator bool () const; // never throwsbool operator! () const; // never throws

T * get() const; // never throwsvoid reset(T * p = 0); // never throwsvoid swap(scoped_ptr & b); // never throws

};

Page 7: C++ templates

std::auto_ptrtemplate < class _Ty > class auto_ptr{public:

template<class _Other> operator auto_ptr<_Other>(){ return (auto_ptr<_Other>(*this)); }

template<class _Other> auto_ptr<_Ty>& operator = (auto_ptr<_Other>& _Right){ reset(_Right.release()); return (*this); }

template<class _Other> auto_ptr(auto_ptr<_Other>& _Right) : _Myptr(_Right.release()){}

_Ty *release(){

_Ty *_Tmp = (_Ty *)_Myptr;_Myptr = 0;return (_Tmp);

}

...};

Page 8: C++ templates

Недостатки глобальных переменных

• Объекты создаются всегда, даже если они не используются

• Порядок инициализации в общем случае неизвестен

• Объекты не разрушаются до завершения программы

• Проблемы с исключениями в конструкторах объектов

Page 9: C++ templates

Singletontemplate < typename T >class Singleton{public:

static T& Instance() {

static T instance;return instance;

}

static const T& ConstInstance(){

return const_cast<const T&>(Instance());}

};

Page 10: C++ templates

Singletonclass A{private:

friend class Singleton<A>;A() {}

public:int a;

};

int main(){

Singleton<A>::Instance().a = 3;std::cout << Singleton<A>::ConstInstance().a << std::endl;return 0;

}

Page 11: C++ templates

Частичная специализация шаблоновtemplate < typename T > T MaxValue();

template < >int MaxValue<int>(){ return INT_MAX; }

template < >float MaxValue<float>(){ return FLT_MAX; }

int main(){

std::cout << "Max int value = " << MaxValue<int>() << std::endl;std::cout << "Max float value = " << MaxValue<float>() << std::endl;return 0;

}

Page 12: C++ templates

Compile time checktemplate <bool b> struct CompileTimeError;template <> struct CompileTimeError<true>{};

CompileTimeError<2 == 4> ERROR_assert_failed;

#define STATIC_CHECK(expr, msg) \{ CompileTimeError<expr> ERROR_##msg; (void)ERROR_##msg; }

int main(){

STATIC_CHECK(2 == 5, assert_failed)return 0;

}

Page 13: C++ templates

Шаблонные шаблонные параметрыtemplate < typename T, template <typename> class Creator = NewCreator >class Singleton{public:

typedef T* InstancePtr;private:

static InstancePtr _instancePtr;

static void Destroy(void){ if(_instancePtr != NULL) Creator<T>::Destroy(_instancePtr); }

public:static T& Instance() {

if(_instancePtr == NULL) { _instancePtr = Creator<T>::Create(); atexit(&Singleton::Destroy); }return *_instancePtr;

}};

template < typename T, template <typename> class C>typename Singleton<T, C>::InstancePtr Singleton<T, C>::_instancePtr = NULL;

Page 14: C++ templates

Шаблонные шаблонные параметрыtemplate <class T> 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 <class T> struct NewCreator{

static T* Create() { return new T; }static void Destroy(T* p) { delete p; }

};

Page 15: C++ templates

Недостатки указателей на функции

• Нет информации о типах аргументов и возвращаемого значения

• Указатель на функцию необходимо перед вызовом проверять на NULL

• Есть возможность привести указатель на функцию к любому указателю

• Разный синтаксис вызова для указателей на функции и указателей на методы

Page 16: C++ templates

Функторы, простая реализацияtemplate < typename Signature >class function;

template < typename R, typename P >class function < R (P) >{

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); }

};

Page 17: C++ templates

Функторы, простая реализацияtemplate <typename ObjType, typename R, typename P1, typename P2>class function < R (ObjType::*) (P1, P2) >{

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); }

};

Page 18: C++ templates

Функторы, простая реализацияstruct A{

char C;

A(char c = ‘X') : C(c) { }

void member_func(double i, bool b){ if (b) std::cout << C << i << std::endl; }

};

int main(){

A a;

function< void (A::*)(double, bool) > f(&A::member_func);f(a, 0.5, true);

function < int (int) > f2(&abs);std::cout << f2(-123) << std::endl;

return 0;}

Page 19: C++ templates

Функторы STL

int main(){

A a;std::mem_fun1_t< void, A, double > f = std::mem_fun(&A::member_func);f(&a, 0.5);

std::mem_fun1_ref_t < void, A, double > f_ref =std::mem_fun_ref(&A::member_func);

f_ref(a, 0.7);

std::pointer_to_unary_function<int, int> f2 = std::ptr_fun(&abs);std::cout << f2(-123) << std::endl;

return 0;}

Page 20: C++ templates

Недостатки функторов STL• Уродливый синтаксис• Отсутствие функторов с большим количеством

параметров• Отсутствует возможность инициализации

функтора с сигнатурой func1 указателем на func2:struct B : public A{};

void func1(B*);void func2(A*);

Page 21: C++ templates

boost::functionint main(){

A a;boost::function < void (A&, double) > f = &A::member_func;f(a, 0.5);

boost::function < int (int) > f2 = &abs;std::cout << f2(-123) << std::endl;

return 0;}

Page 22: C++ templates

Применение функторовvoid generate_int(int& i){ i = rand() % 100 - 50; }

void print_int(int i){ std::cout << i << " "; }

int main(){

std::vector<int> vec(10);std::for_each(vec.begin(), vec.end(), &generate_int);std::for_each(vec.begin(), vec.end(), &print_int);std::cout << std::endl;

std::vector<int> out_vec;std::transform(vec.begin(), vec.end(), std::back_inserter(out_vec), &abs);std::for_each(out_vec.begin(), out_vec.end(), &print_int);std::cout << std::endl;

return 0;}

Page 23: C++ templates

Привязывание параметровint main(){

std::vector<int> vec(10);std::for_each(vec.begin(), vec.end(), &generate_int);std::for_each(vec.begin(), vec.end(), &print_int);std::cout << std::endl;

vec.erase( std::remove_if(vec.begin(), vec.end(), std::bind1st(std::less<int>(), 10)), vec.end() );

std::for_each(vec.begin(), vec.end(), &print_int);std::cout << std::endl;

return 0;}

Page 24: C++ templates

Недостатки std::bind1st/2nd

• Работают только для binary_function• Привязывают только один аргумент• Неудобный синтаксис• Нет возможности привязать ссылку:

void inc (int& n, bool) { ++n; }// ...std::bind1st(std::ptr_fun(&inc), i) (true);

Page 25: C++ templates

boost::bindbool in_range( int min_val, int max_val, int val ){ return (val >= min_val) && (val <= max_val); }

int main(){

// ...

boost::function < bool(int) > pred = boost::bind(&in_range, 5, 15, _1);vec.erase( std::remove_if(vec.begin(), vec.end(), pred), vec.end() );

// ...

return 0;}

Page 26: C++ templates

“Подводные камни” boost::bindclass WindowBase{

typedef boost::function < void (void) > 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;

}

Page 27: C++ templates

Преимущества использования шаблонов C++

• Шаблоны решают проблему дублирования кода

• Зачастую шаблоны позволяют избавиться от динамической диспечеризации и повысить скорость работы приложения

• Позволяют отследить большую часть ошибок на этапе компиляции

• Использование стратегий позволяет не писать сложные классы с нуля, а собирать их из множества меньших

• Можно грабить корованы

Page 28: C++ templates

Список литературы

• Бьерн Страуструп. Язык программирования С++• Скотт Мейерс. Эффективное использование С++• Скотт Мейерс. Наиболее эффективное использование С++• Скотт Мейерс. Эффективное использование STL• Герб Саттер. Решение сложных задач на C++• Герб Саттер. Новые сложные задачи на C++• Андрей Александреску. Современное проектирование на C++• Герб Саттер. Андрей Александреску. Стандарты

программирования на С++. 101 правило и рекомендация• Владимир Сорокин. Голубое сало.