É perfeitamente possível modelar uma classe em um número inteiro em vez de um tipo. Podemos atribuir o valor do modelo a uma variável ou, de outra forma, manipulá-lo de uma forma que faríamos com qualquer outro literal inteiro:
unsignedint x = N;
Na verdade, podemos criar algoritmos que avaliam em tempo de compilação (da Wikipedia ):
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}
Você também pode usar o tipo em static constexpr intvez do seu enum. Portanto, o Factorial<0>modelo teria static constexpr int value = 1, e template <int N> struct Factorialpode terstatic constexpr int value = N * Factorial<N - 1>::value;
bobobobo
@bobobobo isso foi respondido antes do C ++ 11 e constexpr.
Justin Meiners
154
Sim, é um parâmetro sem tipo. Você pode ter vários tipos de parâmetros de modelo
Parâmetros de tipo.
Tipos
Modelos (apenas modelos de classes e alias, sem funções ou modelos de variáveis)
Parâmetros de não tipo
Ponteiros
Referências
Expressões constantes integrais
O que você tem aí é do último tipo. É uma constante de tempo de compilação (chamada de expressão constante) e é do tipo inteiro ou enumeração. Depois de pesquisar no padrão, tive que mover os modelos de classe para a seção de tipos - embora os modelos não sejam tipos. Mas eles são chamados de parâmetros de tipo com o propósito de descrever esses tipos. Você pode ter ponteiros (e também ponteiros de membro) e referências a objetos / funções que têm vínculo externo (aqueles que podem ser vinculados a partir de outros arquivos de objeto e cujo endereço é único em todo o programa). Exemplos:
Parâmetro de tipo de modelo:
template<typename T>structContainer{
T t;};// pass type "long" as argument.Container<long> test;
Parâmetro de modelo inteiro:
template<unsignedint S>structVector{unsignedchar bytes[S];};// pass 3 as argument.Vector<3> test;
Parâmetro de ponteiro de modelo (passando um ponteiro para uma função)
template<void(*F)()>structFunctionWrapper{staticvoid call_it(){ F();}};// pass address of function do_it as argument.void do_it(){}FunctionWrapper<&do_it> test;
Parâmetro de referência do modelo (passando um inteiro)
template<int&A>structSillyExample{staticvoid do_it(){ A =10;}};// pass flag as argumentint flag;SillyExample<flag> test;
Parâmetro do modelo de modelo.
template<template<typename T>classAllocatePolicy>structPool{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){return0;}};Pool<allocator> test;
Um modelo sem parâmetros não é possível. Mas um modelo sem nenhum argumento explícito é possível - ele tem argumentos padrão:
Johannes, os modelos são arquivados em "tipos"? Achei que eles eram de que tipos podem ser feitos, mas não os próprios tipos?
sbi
@sbi veja a explicação: "Depois de pesquisar no padrão, tive que mover os modelos de classe para a seção de tipos - embora os modelos não sejam tipos. Mas eles são chamados de parâmetros de tipo para descrever esses tipos. " A nota de rodapé 126 em 14.1 / 2 diz isso. É apenas uma classificação feita para tornar os parâmetros não-tipo algo que declara um valor / referência e os parâmetros de tipo ser algo que declara um nome de tipo ou nome de modelo.
Johannes Schaub - litb
@ JohannesSchaub-litb então não há como digitar template com, digamos, std :: string? como a classe template <std :: string S> com algum contador estático para criar um id único para cada string diferente? hash string para int seria a única maneira, infelizmente, certo?
relaxxx
1
Adoraria ver esta resposta completada com objetos de membros de classe de modelo, ou seja, modelo <nome do tipo C, nome do tipo R, nome do tipo P1, nome do tipo P2> struct mystruct <R (C :: *) (P1, P2)>
Johnny Pauling
O trecho de código com SillyExamplenão pode ser compilado pelo GCC 4.8.4. O primeiro erro é the value of ‘flag’ is not usable in a constant expression. Existem outros erros também
HEKTO
17
Você cria um modelo para sua classe com base em um 'int não assinado'.
Exemplo:
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.}
Uma classe de modelo é como uma macro, só que muito menos nociva.
Pense em um modelo como uma macro. Os parâmetros do modelo são substituídos em uma definição de classe (ou função), quando você define uma classe (ou função) usando um modelo.
A diferença é que os parâmetros têm "tipos" e os valores passados são verificados durante a compilação, como parâmetros para funções. Os tipos válidos são seus tipos C ++ regulares, como int e char. Ao instanciar uma classe de modelo, você passa um valor do tipo especificado e, em uma nova cópia da definição da classe de modelo, esse valor é substituído onde quer que o nome do parâmetro estivesse na definição original. Exatamente como uma macro.
Você também pode usar os tipos " class" ou " typename" para parâmetros (eles são realmente os mesmos). Com um parâmetro de um desses tipos, você pode passar um nome de tipo em vez de um valor. Assim como antes, em todos os lugares em que o nome do parâmetro estava na definição da classe de modelo, assim que você cria uma nova instância, torna-se o tipo que você passar. Este é o uso mais comum para uma classe de modelo; Todo mundo que sabe alguma coisa sobre modelos C ++ sabe como fazer isso.
Considere este código de exemplo de classe de modelo:
static constexpr int
vez do seuenum
. Portanto, oFactorial<0>
modelo teriastatic constexpr int value = 1
, etemplate <int N> struct Factorial
pode terstatic constexpr int value = N * Factorial<N - 1>::value;
constexpr
.Sim, é um parâmetro sem tipo. Você pode ter vários tipos de parâmetros de modelo
O que você tem aí é do último tipo. É uma constante de tempo de compilação (chamada de expressão constante) e é do tipo inteiro ou enumeração. Depois de pesquisar no padrão, tive que mover os modelos de classe para a seção de tipos - embora os modelos não sejam tipos. Mas eles são chamados de parâmetros de tipo com o propósito de descrever esses tipos. Você pode ter ponteiros (e também ponteiros de membro) e referências a objetos / funções que têm vínculo externo (aqueles que podem ser vinculados a partir de outros arquivos de objeto e cujo endereço é único em todo o programa). Exemplos:
Parâmetro de tipo de modelo:
Parâmetro de modelo inteiro:
Parâmetro de ponteiro de modelo (passando um ponteiro para uma função)
Parâmetro de referência do modelo (passando um inteiro)
Parâmetro do modelo de modelo.
Um modelo sem parâmetros não é possível. Mas um modelo sem nenhum argumento explícito é possível - ele tem argumentos padrão:
Sintaticamente,
template<>
é reservado para marcar uma especialização de modelo explícita, em vez de um modelo sem parâmetros:fonte
SillyExample
não pode ser compilado pelo GCC 4.8.4. O primeiro erro éthe value of ‘flag’ is not usable in a constant expression
. Existem outros erros tambémVocê cria um modelo para sua classe com base em um 'int não assinado'.
Exemplo:
fonte
Uma classe de modelo é como uma macro, só que muito menos nociva.
Pense em um modelo como uma macro. Os parâmetros do modelo são substituídos em uma definição de classe (ou função), quando você define uma classe (ou função) usando um modelo.
A diferença é que os parâmetros têm "tipos" e os valores passados são verificados durante a compilação, como parâmetros para funções. Os tipos válidos são seus tipos C ++ regulares, como int e char. Ao instanciar uma classe de modelo, você passa um valor do tipo especificado e, em uma nova cópia da definição da classe de modelo, esse valor é substituído onde quer que o nome do parâmetro estivesse na definição original. Exatamente como uma macro.
Você também pode usar os tipos "
class
" ou "typename
" para parâmetros (eles são realmente os mesmos). Com um parâmetro de um desses tipos, você pode passar um nome de tipo em vez de um valor. Assim como antes, em todos os lugares em que o nome do parâmetro estava na definição da classe de modelo, assim que você cria uma nova instância, torna-se o tipo que você passar. Este é o uso mais comum para uma classe de modelo; Todo mundo que sabe alguma coisa sobre modelos C ++ sabe como fazer isso.Considere este código de exemplo de classe de modelo:
É funcionalmente igual a este código de macro:
Claro, a versão do modelo é um bilhão de vezes mais segura e mais flexível.
fonte