Os modelos são a base para a realização da programação genérica . Programação genérica refere-se à escrita de códigos lógicos que nada têm a ver com tipos, e é um meio para conseguir reutilização.
Os modelos podem ser divididos em: modelos de função, modelos de classe
Template de função
conceito
O template de função representa uma família de funções. O template de função não tem nenhuma relação com o tipo. Ele é parametrizado quando usado, e uma versão de tipo específico da função é gerada de acordo com o tipo do parâmetro atual.
Formato de modelo de função
template<typename T1,typename T2,……,typename Tn>
返回值类型 函数名(形参列表){
函数体}
Tal como:
template<typename T>
void Swap(T& left,T& right){
T tmp = left;
left = right;
right = tmp;
}//一个可以实现交换功能的函数模板
[Nota]: typename
Também pode ser usado no class
lugar
O princípio do template de função
Um template de função é um molde para o compilador gerar um tipo específico de função, não uma função em si !
Durante a fase de compilação do compilador, quando um modelo de função precisa ser usado para gerar uma função de um tipo específico, o compilador determinará o tipo de entrada T por meio da dedução dos tipos de parâmetros reais e, em seguida, gerará uma função especializada em processar o tipo T.
Tal como:
double a = 3.14, b = 6.28;
int x = 1,y = 2;
char r = 'a', t = 'v';
Swap(a,b);
Swap(x,y);
Swap(r,t);
Por causa Swap
do modelo de função no código, diferentes tipos de dados são passados nas três chamadas e o compilador infere o tipo de cada dado de entrada no estágio e gera as respectivas funções correspondentes .
O código acima terá mais 3 funções na fase de compilação:
void Swap(double& left,double& right){
T tmp = left;
left = right;
right = tmp;
}
void Swap(int& left,int& right){
int tmp = left;
left = right;
right = tmp;
}
void Swap(char& left,char& right){
char tmp = left;
left = right;
right = tmp;
}
Essas três funções correspondem a três chamadas da função Swap respectivamente . Nós apenas escrevemos um modelo de função, mas no código final, diferentes tipos de parâmetros reais serão passados, resultando em muito mais funções. Em outras palavras, o código que usa o modelo tem o problema de inchaço do código.
No entanto, acho que não precisamos de modelos de função para alcançar as mesmas funções para diferentes tipos de dados. Parece que só podemos implementar funções por meio de sobrecarga de função e ainda temos que escrever muitas funções. O uso de modelos libera os desenvolvedores de escrever repetidamente funções da mesma função e de tipos diferentes, o que reduz em certa medida o conteúdo de trabalho ineficiente, mas inevitável, que é de pouca importância para os desenvolvedores, e melhora a eficiência do trabalho. Mesmo que haja um problema com a expansão do código que usa o modelo, parece que ele só se expandirá até o ponto em que o modelo não for usado. Este não é um problema inaceitável.
Instanciação de modelos de função
O processo pelo qual o compilador infere os tipos de argumentos de entrada e gera funções correspondentes para diferentes tipos é chamado de instanciação de modelos de função. A instanciação de modelo pode ser dividida em: instanciação implícita e instanciação explícita
Instanciação implícita
A instanciação implícita significa que o desenvolvedor não informa ao compilador o tipo de argumento transmitido e permite que o compilador deduza que tipo de função ele deve gerar com base no tipo de argumento transmitido . A seguir, não informamos ao compilador que tipo de argumento é passado.
template<typename T>
void Swap(T& left,T& right){
T tmp = left;
left = right;
right = tmp;
}//一个可以实现交换功能的函数模板
int main(){
double a = 3.14, b = 6.28;
Swap(a,b);//隐式实例化
return 0;
}
Instanciação explícita
Para exibir a instanciação, só precisamos <>
preencher o tipo de parâmetro real no nome da função,
como:
Swap<double>(a,b);//显式实例化
Pessoalmente, acho que devemos usar instanciação explícita ao usar modelos de função, para que possamos compreender nosso próprio código e torná-lo mais fácil para os outros lerem.
Princípio de correspondência dos parâmetros do modelo
De modo geral, quando existem funções não-template e funções template que podem completar uma função, existe uma estratégia para ajudar o compilador a decidir como definir a função.
No vernáculo, existem muitos tipos de funções que podem completar a função especificada. Alguns compiladores de função nesta pilha de funções não precisam fazer nada. Corresponde exatamente à lista de parâmetros da função chamada; alguns requerem conversão de tipo implícita; Alguns têm conversões de tipo especificadas pelo desenvolvedor. Neste momento, se você deseja completar uma função, você tem muitas opções. Para evitar erros no resultado e evitar que o compilador salte para a esquerda e para a direita, existe uma estratégia de seleção para ajudar o compilador a escolher a função a ser chamada .
A estratégia de seleção de ajuste é a seguinte (a prioridade é organizada de cima para baixo):
1. Correspondência completa: o modelo de função e a função não modelo existem ao mesmo tempo e podem completar a função especificada, e os tipos não entram em conflito (o o uso de função não-modelo é preferível )
2. Conversão de atualização char
Com conversão short
automática int
, conversão flaot
automática para double
)
3. Conversão padrão ( int
para char, long
para transferir double
)
4. Conversão definida pelo usuário, como a conversão definida na declaração de classe
Limitações de modelos
Suponha que existam as seguintes funções de modelo:
template<typename T>
void f(T a,T b){
//函数体
}
De modo geral, haverá algumas operações na função.
Tal como:
a = b
Se for T
um tipo de dados integrado, essa atribuição estará de acordo com nossas expectativas.
Mas T
para ser um tipo de estrutura array / string / não construído e assim por diante, o resultado provavelmente não atenderá às nossas expectativas.
Outro exemplo:
if(a>b)
Se T
for uma matriz, a>b
a comparação da matriz a
com b
o nível de endereço, provavelmente não é o que queremos.
Resumindo, as funções de modelo podem não ser capazes de lidar com certos tipos.
Precisamos lembrar que tudo tem dois lados! Não há nada absolutamente bom e nada absolutamente ruim.
Modelo de classe
Formato de modelo de classe
template<class T1,class T2,……,class Tn>
class 类模板名
{
//类内成员定义
}
[Nota] Quando os membros da classe no modelo de classe são definidos fora da classe, a lista de parâmetros do modelo precisa ser adicionada
Instanciação do modelo de classe
Diferente da instanciação do modelo de função, a instanciação do modelo de classe precisa ser adicionada após o nome do modelo de classe <>
e, em seguida, o tipo instanciado é colocado <>
. Ou seja, ele deve ser explicitamente instanciado.
A mesma explicação se aplica aos modelos de classe : modelos de classe não são classes! O resultado da instanciação do modelo de classe é a classe!