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 &¶m) —> int &, param - int& lvalue const int —> (T &¶m) —> const int &, param - const int& lvalue const int & —> (T &¶m) —> 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 &¶m) —> 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
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.