C++ templates
-
Upload
mackensie-hinton -
Category
Documents
-
view
16 -
download
2
description
Transcript of C++ templates
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];};
Примеры использования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; }
};
Примеры использованияstruct A{
int a;};
int main(){
auto_ptr<A> 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_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
};
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);
}
...};
Недостатки глобальных переменных
• Объекты создаются всегда, даже если они не используются
• Порядок инициализации в общем случае неизвестен
• Объекты не разрушаются до завершения программы
• Проблемы с исключениями в конструкторах объектов
Singletontemplate < typename T >class Singleton{public:
static T& Instance() {
static T instance;return instance;
}
static const T& ConstInstance(){
return const_cast<const T&>(Instance());}
};
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;
}
Частичная специализация шаблонов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;
}
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;
}
Шаблонные шаблонные параметры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;
Шаблонные шаблонные параметры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; }
};
Недостатки указателей на функции
• Нет информации о типах аргументов и возвращаемого значения
• Указатель на функцию необходимо перед вызовом проверять на NULL
• Есть возможность привести указатель на функцию к любому указателю
• Разный синтаксис вызова для указателей на функции и указателей на методы
Функторы, простая реализация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); }
};
Функторы, простая реализация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); }
};
Функторы, простая реализация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;}
Функторы 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;}
Недостатки функторов STL• Уродливый синтаксис• Отсутствие функторов с большим количеством
параметров• Отсутствует возможность инициализации
функтора с сигнатурой func1 указателем на func2:struct B : public A{};
void func1(B*);void func2(A*);
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;}
Применение функторов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;}
Привязывание параметров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;}
Недостатки std::bind1st/2nd
• Работают только для binary_function• Привязывают только один аргумент• Неудобный синтаксис• Нет возможности привязать ссылку:
void inc (int& n, bool) { ++n; }// ...std::bind1st(std::ptr_fun(&inc), i) (true);
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;}
“Подводные камни” 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;
}
Преимущества использования шаблонов C++
• Шаблоны решают проблему дублирования кода
• Зачастую шаблоны позволяют избавиться от динамической диспечеризации и повысить скорость работы приложения
• Позволяют отследить большую часть ошибок на этапе компиляции
• Использование стратегий позволяет не писать сложные классы с нуля, а собирать их из множества меньших
• Можно грабить корованы
Список литературы
• Бьерн Страуструп. Язык программирования С++• Скотт Мейерс. Эффективное использование С++• Скотт Мейерс. Наиболее эффективное использование С++• Скотт Мейерс. Эффективное использование STL• Герб Саттер. Решение сложных задач на C++• Герб Саттер. Новые сложные задачи на C++• Андрей Александреску. Современное проектирование на C++• Герб Саттер. Андрей Александреску. Стандарты
программирования на С++. 101 правило и рекомендация• Владимир Сорокин. Голубое сало.