Вполне возможно создать шаблон класса для целого числа, а не для типа. Мы можем присвоить шаблонное значение переменной или иным образом манипулировать им так же, как и с любым другим целочисленным литералом:
unsignedint x = N;
Фактически, мы можем создавать алгоритмы, которые оцениваются во время компиляции (из Википедии ):
template<int N>structFactorial{enum{ value = N *Factorial<N -1>::value };};template<>structFactorial<0>{enum{ value =1};};// Factorial<4>::value == 24// Factorial<0>::value == 1void foo(){int x =Factorial<4>::value;// == 24int y =Factorial<0>::value;// == 1}
Вы также можете использовать type static constexpr intвместо вашего enum. Так что в Factorial<0>шаблоне будет static constexpr int value = 1и template <int N> struct Factorialможет бытьstatic constexpr int value = N * Factorial<N - 1>::value;
bobobobo
@bobobobo на это ответили до C ++ 11 и constexpr.
Джастин Майнерс
154
Да, это не типовой параметр. У вас может быть несколько типов параметров шаблона
Параметры типа.
Типы
Шаблоны (только классы и шаблоны псевдонимов, без функций или шаблонов переменных)
Параметры, не относящиеся к типу
указатели
Ссылки
Интегральные постоянные выражения
У вас есть последнее. Это константа времени компиляции (так называемое константное выражение) целого или перечисляемого типа. После поиска в стандарте мне пришлось переместить шаблоны классов в раздел типов, хотя шаблоны не являются типами. Но они, тем не менее, называются параметрами типа для описания этих типов. У вас могут быть указатели (а также указатели членов) и ссылки на объекты / функции, которые имеют внешнюю связь (те, на которые можно ссылаться из других объектных файлов и чей адрес уникален во всей программе). Примеры:
Параметр типа шаблона:
template<typename T>structContainer{
T t;};// pass type "long" as argument.Container<long> test;
Целочисленный параметр шаблона:
template<unsignedint S>structVector{unsignedchar bytes[S];};// pass 3 as argument.Vector<3> test;
Параметр указателя шаблона (передача указателя на функцию)
template<void(*F)()>structFunctionWrapper{staticvoid call_it(){ F();}};// pass address of function do_it as argument.void do_it(){}FunctionWrapper<&do_it> test;
Йоханнес, шаблоны разделены на «типы»? Я думал, из каких типов можно сделать, но не из самих типов?
sbi
@sbi см. объяснение: «После поиска в стандарте мне пришлось переместить шаблоны классов вверх в раздел типов - хотя шаблоны не являются типами. Тем не менее, они называются параметрами типа для описания этих типов. ». Об этом говорится в сноске 126 к 14.1 / 2. Это просто классификация, сделанная для того, чтобы сделать параметры, не являющиеся типами, чем-то, что объявляет значение / ссылку, а параметры типа - тем, что объявляет имя типа или имя шаблона.
Йоханнес Шауб - лит,
@ JohannesSchaub-litb, поэтому нет возможности ввести шаблон, скажем, std :: string? как шаблон <std :: string S> с некоторым статическим счетчиком в нем для создания уникального идентификатора для каждой строки? Хеширование строки в int было бы, к сожалению, единственным способом?
relaxxx
1
Я бы хотел, чтобы этот ответ завершился объектами-членами класса шаблона, то есть template <typename C, typename R, typename P1, typename P2> struct mystruct <R (C :: *) (P1, P2)>
Джонни Полинг
Часть кода с SillyExampleне может быть скомпилирована GCC 4.8.4. Первая ошибка the value of ‘flag’ is not usable in a constant expression. Есть и другие ошибки
HEKTO 06
17
Вы шаблонизируете свой класс на основе unsigned int.
Пример:
template<unsignedint N>classMyArray{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.}
Шаблонный класс похож на макрос, только намного меньше зла.
Думайте о шаблоне как о макросе. Параметры шаблона подставляются в определение класса (или функции), когда вы определяете класс (или функцию) с помощью шаблона.
Разница в том, что параметры имеют «типы», а передаваемые значения проверяются во время компиляции, как параметры для функций. Допустимые типы - это ваши обычные типы C ++, например int и char. Когда вы создаете экземпляр класса шаблона, вы передаете значение указанного вами типа, и в новой копии определения класса шаблона это значение подставляется везде, где имя параметра было в исходном определении. Прямо как макрос.
Вы также можете использовать для параметров типы " class" или " typename" (на самом деле они одинаковы). С параметром одного из этих типов вы можете передать имя типа вместо значения. Как и раньше, везде, где имя параметра было в определении класса шаблона, как только вы создаете новый экземпляр, оно становится любым типом, который вы передаете. Это наиболее частое использование шаблонного класса; Каждый, кто хоть что-нибудь знает о шаблонах C ++, знает, как это сделать.
static constexpr int
вместо вашегоenum
. Так что вFactorial<0>
шаблоне будетstatic constexpr int value = 1
иtemplate <int N> struct Factorial
может бытьstatic constexpr int value = N * Factorial<N - 1>::value;
constexpr
.Да, это не типовой параметр. У вас может быть несколько типов параметров шаблона
У вас есть последнее. Это константа времени компиляции (так называемое константное выражение) целого или перечисляемого типа. После поиска в стандарте мне пришлось переместить шаблоны классов в раздел типов, хотя шаблоны не являются типами. Но они, тем не менее, называются параметрами типа для описания этих типов. У вас могут быть указатели (а также указатели членов) и ссылки на объекты / функции, которые имеют внешнюю связь (те, на которые можно ссылаться из других объектных файлов и чей адрес уникален во всей программе). Примеры:
Параметр типа шаблона:
Целочисленный параметр шаблона:
Параметр указателя шаблона (передача указателя на функцию)
Ссылочный параметр шаблона (передача целого числа)
Параметр шаблона шаблона.
Шаблон без параметров невозможен. Но возможен шаблон без явных аргументов - у него есть аргументы по умолчанию:
Синтаксически
template<>
зарезервировано для обозначения явной специализации шаблона вместо шаблона без параметров:источник
SillyExample
не может быть скомпилирована GCC 4.8.4. Первая ошибкаthe value of ‘flag’ is not usable in a constant expression
. Есть и другие ошибкиВы шаблонизируете свой класс на основе unsigned int.
Пример:
источник
Шаблонный класс похож на макрос, только намного меньше зла.
Думайте о шаблоне как о макросе. Параметры шаблона подставляются в определение класса (или функции), когда вы определяете класс (или функцию) с помощью шаблона.
Разница в том, что параметры имеют «типы», а передаваемые значения проверяются во время компиляции, как параметры для функций. Допустимые типы - это ваши обычные типы C ++, например int и char. Когда вы создаете экземпляр класса шаблона, вы передаете значение указанного вами типа, и в новой копии определения класса шаблона это значение подставляется везде, где имя параметра было в исходном определении. Прямо как макрос.
Вы также можете использовать для параметров типы "
class
" или "typename
" (на самом деле они одинаковы). С параметром одного из этих типов вы можете передать имя типа вместо значения. Как и раньше, везде, где имя параметра было в определении класса шаблона, как только вы создаете новый экземпляр, оно становится любым типом, который вы передаете. Это наиболее частое использование шаблонного класса; Каждый, кто хоть что-нибудь знает о шаблонах C ++, знает, как это сделать.Рассмотрим пример кода этого шаблона класса:
Функционально он такой же, как этот код, использующий макрос:
Конечно, версия шаблона в миллиард раз безопаснее и гибче.
источник