четвер, 19 лютого 2009 р.

Трошки про Шаблони

Шаблони - це сімейство з однаковою поведінкою без конкретизації типу. При використанні шаблонів цей тип передається у вигляді аргументу або проміжно.
Ось типовий приклад:

template < typename T>
inline const T& max(const T& a, const T& b)
{
return a < b : b ? a;
}

Нетипізовані параметри шаблонів
Нетипізований параметр вважається частиною визначення типу.
Наприклад шаблон стандартного класу bitset < > отримує кількість бітів. Зверніть увагу, що ці бітові поля відносяться до різних типів і їх не можна присвоювати один одному:
bitset < 32> flags32;
bitset < 50> flags50;
Параметри по замовчуванню
Наступний фрагмент дозволяє оголосити об'єкти класу MyClass з одним, або двома параметрами:

template < typename T, typename Container = vector< T> >
class MyClass;

MyClass < int> myClass;
MyClass < int, vector< int> > myClass2;

Ключове слово typename
Слово означає, що наступний за ним ідентифікатор означає тип:

template < class T>
class MyClass {
typename T::SubType* ptr;
...
};

В даному випадку слово typename означає, що SubType є підтипом класу T, відповідно ptr - показчик на тип T::SubType. Без typename ідентифікатор SubType інтерпритується як статичний член класу і рядок сприймається як операція множення значення SubType класу T на значення ptr; Але в даному випадку любий тип який буде підставлений шаблону повинен мати внутрішній тип SubType. SubType може бути як класом оголошеним в середині іншого, так і простом typedef-ом.

Шаблонні функції класів
Такі функції не можуть бути віртуальними і мати параметри по замовчуванню!

class MyClass {
...
template < class T>
void f(T);
};

Шаблон MyClass::f оголошує набір функцій з параметром довільного типу, при умові що цей тип підтримує всі операції, які використовуються в f();
Дана можливість часто використовується для автоматичного приведення типів в класах шаблонів. Наприклад в наступному визначенні аргумент x функції assign() повинен точно відповідати типу об"єкта, для якого він викликається:

template < class T>
class MyClass {
private:
T value;
public:
void assign(const MyClass< T>& x) {
value = x.value; // тип x повинен відповідати типові *this
}
};

Зверніть увагу, використання шаблону з іншим типом при виклику assign() являється помилкою навіть в тому випадку якщо між типами виконується автоматичне приведення:

void f()
{
MyClass < double> b;
MyClass < int> i;
d.assign(b); // OK
d.assign(i); // Помилка: i відноситься до до типу MyClass
// в даному випадку обов"язковим є MyClass
}

Оголошення іншого шаблону у функції дозволяє обійти вимогу співпадіння типів:

template < class T>
class MyClass {
private:
T value;
public:
template < class X>
void assign(const MyClass< X>& x) {
value = x.getValue();
}
T getValue() const {
return value;
}
...
};

тепер функція f() є вірною.
Оскільки тип аргументу x не є типом *this, нам довелося додати функцію getValue() для доступу до приватної змінної.

Шаблонний конструктор використовуються для забезпечення неявних приведень типів при копіюванні об"єктів, але майте на увазі, шаблонний конструктор не заміняє стандартний конструктор копіювання. При точному співпадінні типів буде викликаний стандартний конструктор копіювання:

template < class T>
class MyClass {
public:
// Шаблонний конструктор з автоматичним приведенням тиу
template < class X>
MyClass(const MyClass< X>& x);
};
void f()
{
MyClass < double> xd;
...
MyClass < double> xd2(xd); // Стандартний конструктор копії
MyClass < int> xi(xd); // Шаблонний конструктор
}

Явна ініціалізація базових типів була реалізована для того, щоб ви могли написати код шаблону в якому величині любого типу буде попередньо присвоєне значення по замовчуванню.
Виклик конструктора гарантує, що для всіх базових типів змінна x буде ініціалізована нулем.

template < class T>
void f()
{
T x = T();
...
int i = int(); // ініціалізація змінної i нулем
}

Явна спеціалізація шаблонів.

Хочу звернути увагу на одну особливість використання явної спеціалізації з компілятором майкрософт візуал студіо та компілятором gcc.

#include < iostream>
using namespace std;

class MyClass
{
public:
MyClass() {}
~MyClass() {}
enum State { NoneState = 0x0,
Edited = 0x1,
Inserted = 0x2,
Removed = 0x4,
Saved = 0x8 };
State m_state;
template < State state> void setState() {
cout < < "Usual setState template!!!!" < < endl;
}
///////////// Explicid Specialization for State::Saved
template < > void setState< Saved>() {
cout < < "Explicid Specialication for Saved!!!!" < < endl;
}
};
int main()
{
MyClass m;
m.setState< MyClass::Removed>();
m.setState< MyClass::Saved>();
return 0;
}

Зверніть увагу на рядок

template < > void setState< Saved>() {
cout < < "Explicid Specialication for Saved!!!!" < < endl;
}

Компілятор візуал студіо 2005 без будть яких проблем допускає оголошення явної спеціалізації в середині класу, а от gcc (у мому випадку версії 4.3.0) видає наступну помилку:
error: explicit specialization in non-namespace scope ‘class MyClass’
Тому краще оголосити явну спеціалізацію за межами класу, як це потрібно:

class MyClass
{...
};
///////////// Explicid Specialization for State::Saved
template < > void MyClass::setState< MyClass::Saved>() {
cout < < "Explicid Specialication for Saved!!!!" < < endl;
}

Матеріал взято із книги Nicolai M.Josuttis The C++ Standard Library

1 коментар:

  1. Всім привіт, я Адорян Адельмо з села Ясіня в україні, і я просто хочу висловити величезну подяку службам фінансових позик pedro за їх щирість, відкритість, прозорість, правдивість, любов та підтримку під час і після отримання від них кредитних коштів. Я пережив багато чого в житті, і час не дозволить мені сказати все, що я пережив у рік пандемії, але Бог відповів на мої молитви завдяки підтримці та любові від служб фінансових позик Pedro, які обійняли мене та зрозумів мене, незважаючи на мої початкові сумніви та несерйозність, і з його добрим серцем і любов'ю я тепер власник житла через його 3 позичкові фонди з процентними ставками, і я обіцяю поширювати цю новину, а також розповісти світу, що в Інтернеті все ще є справжніх і мало хороших кредитні фірми, які можуть допомогти, а також оживити сухі кістки, як я. не забудьте послухати і прочитати це свідчення, тому що це справжній досвід, що змінює життя, і будь-хто, хто потребує такого повороту, не повинен вагатися або сумніватися в цьому, тому що я довів і клянусь Богом на небесах, що ця історія реальна і також історія мого досвіду з ними. зв’яжіться з ними сьогодні, щоб отримати консолідований кредит, бізнес-позику, житловий кредит, автокредит, особисту позику. електронна пошта: pedroloanss@gmail.com whats-app: +1- 8632310632

    ВідповістиВидалити

Прихильники