19.2 – Шаблонные параметры, не являющиеся типами данных

Добавлено 22 августа 2021 в 22:30

В предыдущих уроках вы узнали, как использовать шаблонные параметры типа для создания функций и классов, не зависящих от типа. Шаблонный параметр типа – это тип-заполнитель, который заменяет тип, переданный в качестве аргумента.

Однако шаблонные параметры типа – не единственный доступный тип параметров шаблонов. Шаблоны классов и функций могут использовать другой тип шаблонного параметра, известный как параметр, не являющийся типом (non-type parameter).

Параметры, не являющиеся типами

Шаблонный параметр, не являющийся типом, – это параметр шаблона, в котором тип параметра предопределен, и он заменяется значением constexpr, переданным в качестве аргумента.

Параметр, не являющийся типом, может быть любого из следующих типов:

  • целочисленный тип;
  • перечисление;
  • указатель или ссылка на объект класса;
  • указатель или ссылка на функцию;
  • указатель или ссылка на функцию-член класса;
  • std::nullptr_t;
  • тип с плавающей запятой (начиная с C++20).

В следующем примере мы создаем класс нединамического (статического) массива, который использует как параметр типа, так и параметр, не являющийся типом. Параметр типа управляет типом данных статического массива, а целочисленный параметр, не являющийся типом, определяет размер статического массива.

#include <iostream>
 
// size является целочисленным параметром, не являющимся типом
template <typename T, int size> 
class StaticArray
{
private:
    // Параметр, не являющийся типом, управляет размером массива
    T m_array[size] {};
 
public:
    T* getArray();
	
    T& operator[](int index)
    {
        return m_array[index];
    }
};
 
// Показываем, как функция для класса с параметром,
// не являющимся типом, определяется вне класса
template <typename T, int size>
T* StaticArray<T, size>::getArray()
{
    return m_array;
}
 
int main()
{
    // объявляем массив из int с местом для 12 целых чисел
    StaticArray<int, 12> intArray;
 
    // Заполняем его по порядку, а затем
    // распечатываем в обратном направлении
    for (int count { 0 }; count < 12; ++count)
        intArray[count] = count;
 
    for (int count { 11 }; count >= 0; --count)
        std::cout << intArray[count] << ' ';
    std::cout << '\n';
 
    // объявляем буфер для double с местом для 4 значений double
    StaticArray<double, 4> doubleArray;
 
    for (int count { 0 }; count < 4; ++count)
        doubleArray[count] = 4.4 + 0.1 * count;
 
    for (int count { 0 }; count < 4; ++count)
        std::cout << doubleArray[count] << ' ';
 
    return 0;
}

Этот код печатает следующее:

11 10 9 8 7 6 5 4 3 2 1 0
4.4 4.5 4.6 4.7

В приведенном выше примере примечательно то, что нам не нужно динамически размещать переменную-член m_array! Это связано с тем, что для любого заданного экземпляра класса StaticArray размер должен быть constexpr (константой времени компиляции). Например, если вы создаете экземпляр StaticArray<int, 12>, компилятор заменит size на 12. Таким образом, m_array имеет тип int[12], который может размещаться статически.

Эта функциональность используется классом стандартной библиотеки std::array. Когда вы размещаете std::array<int, 5>, int – это параметр типа, а 5 – это параметр, не являющийся типом!

Обратите внимание, что если вы попытаетесь создать экземпляр шаблона с параметром, не являющимся типом, со значением, отличным от constexpr, это не сработает:

template <int size>
class Foo
{
};
 
int main()
{
    int x{ 4 }; // x не является constexpr (константой времени компиляции)
    Foo<x> f;   // ошибка: аргумент шаблона, не являющийся типом, должен быть constexpr
 
    return 0;
}

В таком случае компилятор выдаст ошибку.

Теги

C++ / CppLearnCppstd::arrayДля начинающихКласс (программирование)ОбучениеПрограммированиеШаблон / TemplateШаблон класса

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.