С++ для начинающих

       

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


Параметр шаблона класса может и не быть типом. На аргументы, подставляемые вместо таких параметров, накладываются некоторые ограничения. В следующем примере  мы изменяем определение класса 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;   // правильно


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


  • 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;


    Содержание раздела