Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Аргументы шаблона для параметров-констант



Параметр шаблона класса может и не быть типом. На аргументы, подставляемые вместо таких параметров, накладываются некоторые ограничения. В следующем примере мы изменяем определение класса Screen (см. главу 13) на шаблон, параметризованный высотой и шириной:

template < int hi, int wid>

class Screen {

public:

Screen(): _height( hi ), _width( wid ), _cursor ( 0 ),

         _screen( hi * wid, '#' )

       { }

//...

private:

string       _screen;

string:: size_type _cursor;

short        _height;

short        _width;

};

 

typedef Screen< 24, 80> termScreen;

termScreen hp2621;

 

Screen< 8, 24> ancientScreen;

Выражение, с которым связан параметр, не являющийся типом, должно быть константным, т.е. вычисляемым во время компиляции. В примере выше typedef termScreen ссылается на экземпляр шаблона Screen< 24, 80>, где аргумент шаблона для hi равен 24, а для wid – 80. В обоих случаях аргумент – это константное выражение.

Однако для шаблона BufPtr конкретизация приводит к ошибке, так как значение указателя, получающееся при вызове оператора new(), становится известно только во время выполнения:

template < int *ptr> class BufPtr {... };

 

// ошибка: аргумент шаблона нельзя вычислить во время компиляции

BufPtr< new int[24] > bp;

Не является константным выражением и значение неконстантного объекта. Его нельзя использовать в качестве аргумента для параметра-константы шаблона. Однако адрес любого объекта в области видимости пространства имен, в отличие от адреса локального объекта, является константным выражением (даже если спецификатор const отсутствует), поэтому его можно применять в качестве аргумента для параметра-константы. Константным выражением будет и значение оператора sizeof:

template < int size> Buf {... };

template < int *ptr> class BufPtr {... };

 

int size_val = 1024;

const int c_size_val = 1024;

 

Buf< 1024 > buf0; // правильно

Buf< c_size_val > buf1; // правильно

Buf< sizeof(size_val) > buf2; // правильно: sizeof(int)

BufPtr< & size_val > bp0; // правильно

 

// ошибка: нельзя вычислить во время компиляции

Buf< size_val > buf3;

Вот еще один пример, иллюстрирующий использование параметра-константы для представления константного значения в определении шаблона, а также применение его аргумента для задания значения этого параметра:

template < class Type, int size >

class FixedArray {

public:

FixedArray( Type *ar ): count( size )

{

for ( int ix = 0; ix < size; ++ix )

     array[ ix ] = ar[ ix ];

}

private:

Type array[ size ];

int count;

};

 

int ia[4] = { 0, 1, 2, 3 };

FixedArray< int, sizeof( is ) / sizeof( int ) > iA{ ia );

Выражения с одинаковыми значениями считаются эквивалентными аргументами для параметров-констант шаблона. Так, все три экземпляра Screen ссылаются на один и тот же конкретизированный из шаблона класс Screen< 24, 80>:

const int width = 24;

const int height = 80;

 

// все это Screen< 24, 80 >

Screen< 2*12, 40*2 > scr0;

Screen< 6+6+6+6, 20*2 + 40 > scr1;

Screen< width, height > scr2;

Между типом аргумента шаблона и типом параметра-константы допустимы некоторые преобразования. Их множество является подмножеством преобразований, допустимых для аргументов функции:

· трансформации l-значений, включающие преобразование l-значения в r-значение, массива в указатель и функции в указатель:

template < int *ptr> class BufPtr {... };

 

int array[10];

BufPtr< array > bpObj; // преобразование массива в указатель

· преобразования квалификаторов:

template < const int *ptr> class Ptr {... };

 

int iObj;

Ptr< & iObj > pObj; // преобразование из int* в const int*

· расширения типов:

template < int hi, int wid> class Screen {... };

 

const short shi = 40;

const short swi = 132;

Screen< shi, swi > bpObj2; // расширения типа short до int

· преобразования целых типов:

template < unsigned int size> Buf{... };

 

Buf< 1024 > bpObj; // преобразование из int в unsigned int

(Более подробно они описаны в разделе 9.3.)

Рассмотрим следующие объявления:

extern void foo( char * );

extern void bar( void * );

typedef void (*PFV)( void * );

const unsigned int x = 1024;

 

template < class Type,

     unsigned int size,

     PFV handler> class Array {... };

 

Array< int, 1024U, bar> a0; // правильно: преобразование не нужно

Array< int, 1024U, foo> a1; // ошибка: foo! = PFV

 

Array< int, 1024, bar> a2;   // правильно: 1024 преобразуется в unsigned int

Array< int, 1024, bar> a3; // ошибка: foo! = PFV

 

Array< int, x, bar> a4;   // правильно: преобразование не нужно

Array< int, x, foo> a5;   // ошибка: foo! = PFV

Объекты a0 и a4 класса Array определены правильно, так как аргументы шаблона точно соответствуют типам параметров. Объект a2 также определен правильно, потому что аргумент 1024 типа int приводится к типу unsigned int параметра-константы size с помощью преобразования целых типов. Объявления a1, a3 и a5 ошибочны, так как не существует преобразования между любыми двумя типами функций.

Приведение значения 0 целого типа к типу указателя недопустимо:

template < int *ptr>

class BufPtr {... };

 

// ошибка: 0 имеет тип int

// неявное преобразование в нулевой указатель не применяется

BufPtr< 0 > nil;

Упражнение 16.3

Укажите, какие из данных конкретизированных шаблонов действительно приводят к конкретизации:

template < class Type >

class Stack { };

 

void f1( Stack< char > ); // (a)

 

class Exercise {

//...

Stack< double > & rsd; // (b)

Stack< int > si; // (c)

};

 

int main() {

Stack< char > *sc; // (d)

f1( *sc );          // (e)

 

int iObj = sizeof( Stack< string > ); // (f)

}

Упражнение 16.4

Какие из следующих конкретизаций шаблонов корректны? Почему?

template < int *ptr > class Ptr (... };

template < class Type, int size > class Fixed_Array {... };

template < int hi, int wid > class Screen {... };

(a) const int size = 1024;

Ptr< & size > bp1;

(b) int arr[10];

Ptr< arr > bp2;

 (c) Ptr < 0 > bp3;

(d) const int hi = 40;

const int wi = 80;

Screen< hi, wi+32 > sObj;

(e) const int size_val = 1024;

Fixed_Array< string, size_val > fa1;

(f) unsigned int fasize = 255;

Fixed_Array< int, fasize > fa2;

(g) const double db = 3.1415;

Fixed_Array< double, db > fa3;


Поделиться:



Последнее изменение этой страницы: 2019-04-09; Просмотров: 307; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.019 с.)
Главная | Случайная страница | Обратная связь