Слайд 2Синтаксис
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];
};
Слайд 3Примеры использования
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; }
};
Слайд 4Примеры использования
struct A
{
int a;
};
int main()
{
auto_ptr p_a = new A;
(*p_a).a =
9;
int i = p_a->a;
return 0;
}
Слайд 5smart pointers
std::auto_ptr – лучше не использовать
_com_ptr_t – для COM-интерфейсов
boost::scoped_ptr – некопируемый
boost::shared_ptr
– копируемый, использует подсчёт ссылок
boost::weak_ptr – решает проблему «кольцевых ссылок»
Слайд 6boost:: 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
};
Слайд 7std::auto_ptr
template < class _Ty > class auto_ptr
{
public:
template operator auto_ptr()
{ return
(auto_ptr<_Other>(*this)); }
template auto_ptr<_Ty>& operator = (auto_ptr<_Other>& _Right)
{ reset(_Right.release()); return (*this); }
template auto_ptr(auto_ptr<_Other>& _Right) : _Myptr(_Right.release())
{}
_Ty *release()
{
_Ty *_Tmp = (_Ty *)_Myptr;
_Myptr = 0;
return (_Tmp);
}
...
};
Слайд 8Недостатки глобальных переменных
Объекты создаются всегда, даже если они не используются
Порядок инициализации
в общем случае неизвестен
Объекты не разрушаются до завершения программы
Проблемы с исключениями в конструкторах объектов
Слайд 9Singleton
template < typename T >
class Singleton
{
public:
static T& Instance()
{
static T instance;
return
instance;
}
static const T& ConstInstance()
{
return const_cast(Instance());
}
};
Слайд 10Singleton
class A
{
private:
friend class Singleton;
A() {}
public:
int a;
};
int main()
{
Singleton::Instance().a = 3;
std::cout
<< std::endl;
return 0;
}
Слайд 11Частичная специализация шаблонов
template < typename T >
T MaxValue();
template < >
int
MaxValue()
{ return INT_MAX; }
template < >
float MaxValue()
{ return FLT_MAX; }
int main()
{
std::cout << "Max int value = " << MaxValue() << std::endl;
std::cout << "Max float value = " << MaxValue() << std::endl;
return 0;
}
Слайд 12Compile time check
template struct CompileTimeError;
template struct CompileTimeError{};
CompileTimeError
4> ERROR_assert_failed;
#define STATIC_CHECK(expr, msg) \
{ CompileTimeError ERROR_##msg; (void)ERROR_##msg; }
int main()
{
STATIC_CHECK(2 == 5, assert_failed)
return 0;
}
Слайд 13Шаблонные шаблонные параметры
template < typename T, 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 < typename T, template class C>
typename Singleton::InstancePtr Singleton::_instancePtr = NULL;
Слайд 14Шаблонные шаблонные параметры
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; }
};
Слайд 15Недостатки указателей на функции
Нет информации о типах аргументов и возвращаемого значения
Указатель
на функцию необходимо перед вызовом проверять на NULL
Есть возможность привести указатель на функцию к любому указателю
Разный синтаксис вызова для указателей на функции и указателей на методы
Слайд 16Функторы, простая реализация
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); }
};
Слайд 17Функторы, простая реализация
template
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); }
};
Слайд 18Функторы, простая реализация
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;
}
Слайд 19Функторы 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 f2 = std::ptr_fun(&abs);
std::cout << f2(-123) << std::endl;
return 0;
}
Слайд 20Недостатки функторов STL
Уродливый синтаксис
Отсутствие функторов с большим количеством параметров
Отсутствует возможность инициализации
функтора с сигнатурой func1 указателем на func2:
struct B : public A{};
void func1(B*);
void func2(A*);
Слайд 21boost::function
int 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;
}
Слайд 22Применение функторов
void generate_int(int& i)
{ i = rand() % 100 - 50;
}
void print_int(int i)
{ std::cout << i << " "; }
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::endl;
std::vector 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;
}
Слайд 23Привязывание параметров
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
vec.end(),
std::bind1st(std::less(), 10)), vec.end() );
std::for_each(vec.begin(), vec.end(), &print_int);
std::cout << std::endl;
return 0;
}
Слайд 24Недостатки std::bind1st/2nd
Работают только для binary_function
Привязывают только один аргумент
Неудобный синтаксис
Нет возможности привязать
ссылку:
void inc (int& n, bool) { ++n; }
// ...
std::bind1st(std::ptr_fun(&inc), i) (true);
Слайд 25boost::bind
bool 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;
}
Слайд 26“Подводные камни” boost::bind
class 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;
}
Слайд 27Преимущества использования шаблонов C++
Шаблоны решают проблему дублирования кода
Зачастую шаблоны позволяют избавиться
от динамической диспечеризации и повысить скорость работы приложения
Позволяют отследить большую часть ошибок на этапе компиляции
Использование стратегий позволяет не писать сложные классы с нуля, а собирать их из множества меньших
Можно грабить корованы
Слайд 28Список литературы
Бьерн Страуструп. Язык программирования С++
Скотт Мейерс. Эффективное использование С++
Скотт Мейерс.
Наиболее эффективное использование С++
Скотт Мейерс. Эффективное использование STL
Герб Саттер. Решение сложных задач на C++
Герб Саттер. Новые сложные задачи на C++
Андрей Александреску. Современное проектирование на C++
Герб Саттер. Андрей Александреску. Стандарты программирования на С++. 101 правило и рекомендация
Владимир Сорокин. Голубое сало.