O padrão C ++ 17 apresenta "guias de dedução de modelo". Percebi que eles têm algo a ver com a nova dedução de argumento de modelo para construtores introduzida nesta versão do padrão, mas eu ainda não vi uma explicação simples no estilo FAQ sobre o que eles são e para que servem.
O que são guias de dedução de modelo em C ++ 17?
Por que (e quando) precisamos deles?
Como posso declará-los?
Respostas:
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>
'sT
tipo será. Nós sabemos qual é a resposta;T
deveria sertypename std::iterator_traits<Iterator>::value_type
. Mas como podemos dizer ao compilador sem ter que digitarvector<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á avector
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 uminitializer_list
usa explicitamente ovector
'sT
, 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"}; //thing.t is a `std::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.
fonte
vector v{first, last};
não fará a coisa certa :(std::string{32,'*'}[0] == ' '
(para ASCII). Mas tudo isso é verdade desde o C ++ 11.