1. Baseado em Meyers “c ++ efetivo e moderno” - inferência de tipo de modelo

Boa tarde, querido leitor!


Este artigo é o primeiro de uma série de artigos abstratos que escreverei ao ler o livro de Scott Meyers, Effective and Modern c ++. Cada um desses artigos terá um diretório separado em um projeto especialmente instituído no github.com com exemplos de uso dos recursos e técnicas descritos.


Inferência de tipo de modelo


O design de sucesso é quando o consumidor não sabe como o dispositivo funciona, mas tudo lhe convém.


A conclusão do tipo de modelo é quando existe uma função de modelo, por exemplo, e é chamada sem nenhum modelo e colchetes angulares. Ao mesmo tempo, o compilador adivinha que tipo ele precisará usar em um objeto específico da função.


Meyers divide o tipo - "T" , que é exibido, e o tipo - "ParamType" , prescrito pelo programador na definição do parâmetro.


1. Visualização de parâmetros - link ou ponteiro


Para entender rapidamente a regra de derivação, eu a refletirei na forma de um modelo:


tipo de entrada -> tipo, parâmetro -> tipo de saída [, tipo final de parâmetro ]


Exemplo com um link:


template<typename T> //   T void func(T& param) //   - T& int x = 0; //   int func(x); 

Ao emitir um tipo T, a referência (*, &) é descartada porque já está especificada ao definir a função, como se isso significasse "você passa alguma coisa lá, assumiremos que este não é um link, porque a referência já foi adicionada no local de consumo - na nossa função f "


Pelo mesmo princípio, a constância é descartada se for especificada no parâmetro de função. Em links, ponteiros, constância, por assim dizer, uma máscara exclusiva é imposta.


Regime de retirada


 //   int —> (T & param) —> int; const int —> (T & param) —> const int; const int & —> (T & param) —> const int //   int —> (const T & param) —> int; const int —> (const T & param) —> int; const int & —> (const T & param) —> int; //   int * —> (T * param) —> int; const int —> (T * param) —> const int; const int * —> (T * param) —> const int; //   int * —> (const T * param) —> int; const int —> (const T * param) —> int; const int * —> (const T * param) —> int; 

2. Tipo de argumento - referência universal


Scott menciona que os links universais serão considerados mais tarde; portanto, as regras para os parâmetros que ele divide aqui em rvalue e lvalue só precisam ser lembradas com pouco pensamento.


 template<typename T> void func(const T&& param) 

Regras de inferência para lvalue


Scott afirma que esse é o único caso em que T é emitido como referência.
Nos exemplos a seguir, o tipo do parâmetro na descrição da função é uma referência universal de valor . Pode-se observar que T é exibido como um link ou um link constante, dependendo
a partir do argumento de entrada, o tipo do parâmetro param também é uma referência neste caso.


 lvalue int —> (T &&param) —> int &, param - int& lvalue const int —> (T &&param) —> const int &, param - const int& lvalue const int & —> (T &&param) —> const int &, param - const int& 

O tipo do parâmetro em si também é substituído. Acho que isso se deve ao fato de a linguagem não poder considerar uma variável lvalue alocada em algum lugar acima da que pode ser movida ainda mais. Descobriremos isso depois quando chegarmos a links universais.
Para verificar se T é realmente uma referência de tipo, escrevi T myVar no corpo da função de modelo, que este T exibia e esperava receber uma mensagem - "declarada como referência, mas não inicializada" - no link :)


Regras de inferência para rvalue


As regras "normais" do parágrafo 1 são aplicáveis.


 rvalue int —> (T &&param) —> int, param - int&& 

Já é evidente que as referências universais são “incluídas” apenas para objetos rvalue-temporários; em outros casos, quando o argumento não é uma referência universal, rvalue, lvalue não é distinguido


3. Passe por valor (como está)


Ao passar por valor, a constância e a referencialidade do argumento original são descartadas como desnecessárias porque esses são objetos independentes completamente novos, por que eles precisam de qualificadores do que não estão conectados?


 int —> (T param) —> int const int —> (T param) —> int const int & —> (T param) —> int //       ,     const char * const —> (T param) —> const char * 

Suponho que outras combinações loucas e ilógicas causem erros de compilação; quase sempre, ao que parece, o trabalho do compilador é compreensível, você só precisa ouvir essas explicações uma vez.

Source: https://habr.com/ru/post/pt414233/


All Articles