Guias de dedução de modelo são padrões associados a uma classe de modelo que informa ao compilador como traduzir um conjunto de argumentos do construtor (e seus tipos) em parâmetros de modelo para a classe.
O exemplo mais simples é aquele de std::vector
e seu construtor que recebe um par de iteradores.
template<typename Iterator>
void func(Iterator first, Iterator last)
{
vector v(first, last);
}
O compilador precisa descobrir o que vector<T>
's T
tipo será. Nós sabemos qual é a resposta; T
deveria ser typename std::iterator_traits<Iterator>::value_type
. Mas como podemos dizer ao compilador sem ter que digitar vector<typename std::iterator_traits<Iterator>::value_type>
?
Você usa um guia de dedução:
template<typename Iterator> vector(Iterator b, Iterator e) ->
vector<typename std::iterator_traits<Iterator>::value_type>;
Isso diz ao compilador que, ao chamar um vector
construtor que corresponda a esse padrão, ele deduzirá a vector
especialização usando o código à direita de ->
.
Você precisa de guias quando a dedução do tipo dos argumentos não é baseada no tipo de um desses argumentos. Inicializar um a vector
partir de um initializer_list
usa explicitamente o vector
's T
, então não precisa de um guia.
O lado esquerdo não especifica necessariamente um construtor real. A maneira como funciona é que, se você usar a dedução do construtor de modelo em um tipo, ela corresponderá aos argumentos que você passar contra todos os guias de dedução (os construtores reais do modelo principal fornecem guias implícitos). Se houver uma correspondência, ele a usa para determinar quais argumentos de modelo fornecer ao tipo.
Mas uma vez que essa dedução é feita, uma vez que o compilador descobre os parâmetros do template para o tipo, a inicialização para o objeto daquele tipo continua como se nada disso tivesse acontecido. Ou seja, o guia de dedução selecionado não precisa corresponder ao construtor selecionado.
Isso também significa que você pode usar guias com agregados e inicialização de agregados:
template<typename T>
struct Thingy
{
T t;
};
Thingy(const char *) -> Thingy<std::string>;
Thingy thing{"A String"};
Portanto, os guias de dedução são usados apenas para descobrir o tipo que está sendo inicializado. O processo real de inicialização funciona exatamente como antes, uma vez que a determinação foi feita.