Что означает шаблон <unsigned int N>?
При объявлении шаблона я использую такой код:
template <class T>
Но в этом вопросе они использовали:
template <unsigned int N>
Я проверил, что он компилируется. Но что это значит? Является ли это непиговым параметром? И если да, то как мы можем создать шаблон без какого-либо параметра типа?
Ответы
Ответ 1
Совершенно возможно создать шаблон класса по целому, а не по типу. Мы можем назначить шаблонное значение переменной или иным образом манипулировать ею так, как мы могли бы с любым другим целым литералом:
unsigned int x = N;
Фактически мы можем создавать алгоритмы, которые оцениваются во время компиляции (из Wikipedia):
template <int N>
struct Factorial
{
enum { value = N * Factorial<N - 1>::value };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
};
// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
int x = Factorial<4>::value; // == 24
int y = Factorial<0>::value; // == 1
}
Ответ 2
Да, это параметр не-типа. Вы можете иметь несколько типов параметров шаблона
- Введите параметры.
- Типы
- Шаблоны (только классы и шаблоны псевдонимов, без функций или шаблонов переменных)
- Неигровые параметры
- Указатели
- Ссылки
- Интегральные константные выражения
У вас есть последний вид. Это константа времени компиляции (так называемое постоянное выражение) и имеет тип integer или перечисление. После поиска в стандарте мне пришлось переместить классные шаблоны в раздел типов - хотя шаблоны не являются типами. Но они называются параметрами типа с целью описания тех видов. У вас могут быть указатели (а также указатели элементов) и ссылки на объекты/функции, которые имеют внешнюю привязку (те, которые могут быть связаны с другими объектными файлами и адрес которых уникален во всей программе). Примеры:
Параметр типа шаблона:
template<typename T>
struct Container {
T t;
};
// pass type "long" as argument.
Container<long> test;
Параметр целочисленного шаблона:
template<unsigned int S>
struct Vector {
unsigned char bytes[S];
};
// pass 3 as argument.
Vector<3> test;
Параметр указателя шаблона (передача указателя на функцию)
template<void (*F)()>
struct FunctionWrapper {
static void call_it() { F(); }
};
// pass address of function do_it as argument.
void do_it() { }
FunctionWrapper<&do_it> test;
Параметр ссылки шаблона (передача целого числа)
template<int &A>
struct SillyExample {
static void do_it() { A = 10; }
};
// pass flag as argument
int flag;
SillyExample<flag> test;
Параметр шаблона шаблона.
template<template<typename T> class AllocatePolicy>
struct Pool {
void allocate(size_t n) {
int *p = AllocatePolicy<int>::allocate(n);
}
};
// pass the template "allocator" as argument.
template<typename T>
struct allocator { static T * allocate(size_t n) { return 0; } };
Pool<allocator> test;
Шаблон без каких-либо параметров невозможен. Но шаблон без явного аргумента возможен - он имеет аргументы по умолчанию:
template<unsigned int SIZE = 3>
struct Vector {
unsigned char buffer[SIZE];
};
Vector<> test;
Синтаксически template<>
зарезервировано для обозначения явной специализации шаблона вместо шаблона без параметров:
template<>
struct Vector<3> {
// alternative definition for SIZE == 3
};
Ответ 3
Вы templatize своего класса на основе "unsigned int".
Пример:
template <unsigned int N>
class MyArray
{
public:
private:
double data[N]; // Use N as the size of the array
};
int main()
{
MyArray<2> a1;
MyArray<2> a2;
MyArray<4> b1;
a1 = a2; // OK The arrays are the same size.
a1 = b1; // FAIL because the size of the array is part of the
// template and thus the type, a1 and b1 are different types.
// Thus this is a COMPILE time failure.
}
Ответ 4
Класс шаблона похож на макрос, только намного меньше зла.
Подумайте о шаблоне как макросе. Параметры шаблона заменяются на определение класса (или функции) при определении класса (или функции) с использованием шаблона.
Отличие состоит в том, что параметры имеют "типы" и переданные значения проверяются во время компиляции, как параметры для функций. Допустимыми типами являются ваши обычные типы С++, такие как int и char. Когда вы создаете экземпляр класса шаблона, вы передаете значение указанного вами типа, а в новой копии определения класса шаблона это значение заменяется там, где имя параметра находилось в исходном определении. Также как макрос.
Вы также можете использовать типы "class
" или "typename
" для параметров (они действительно одинаковы). С параметром одного из этих типов вы можете передать имя типа вместо значения. Как и раньше, везде имя параметра находилось в определении класса шаблона, как только вы создаете новый экземпляр, становится тем типом, который вы передаете. Это наиболее распространенное использование для класса шаблона; Все, кто что-то знает о шаблонах на С++, знают, как это сделать.
Рассмотрим этот пример кода примера шаблона:
#include <cstdio>
template <int I>
class foo
{
void print()
{
printf("%i", I);
}
};
int main()
{
foo<26> f;
f.print();
return 0;
}
Он функционально совпадает с этим макрокомандом:
#include <cstdio>
#define MAKE_A_FOO(I) class foo_##I \
{ \
void print() \
{ \
printf("%i", I); \
} \
};
MAKE_A_FOO(26)
int main()
{
foo_26 f;
f.print();
return 0;
}
Конечно, версия шаблона в миллиард раз безопаснее и гибче.