O que são guias de dedução de modelo e quando devemos usá-los?

87

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?

Tristan Brindle
fonte
Em particular, eu estaria interessado em saber se algum guia de dedução é realmente fornecido pelo C ++ 17 STL (por exemplo, para std :: pair ou std :: tuple). Qual é a lista completa de tipos de modelo padrão "dedutíveis" em C ++ 17?
Quuxplusone
Eu estaria interessado em saber se algum compilador suporta isso. Tentei gcc, clang e vc ++. rextester.com/DHPHC32332 Deixa pra lá , descobri que funciona apenas com gc ++ 8.1 C ++ 17 e 2a g ++ -std = c ++ 17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
Jean-Simon Brochu

Respostas:

98

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::vectore 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 Ttipo será. Nós sabemos qual é a resposta; Tdeveria 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 vectorconstrutor que corresponda a esse padrão, ele deduzirá a vectorespecializaçã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 vectorpartir de um initializer_listusa 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"}; //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.

Nicol Bolas
fonte
7
Hmm, acabei de me ocorrer que mesmo com o guia, vector v{first, last};não fará a coisa certa :(
TC
3
@TC… a menos que a coisa certa seja fazer um vetor de iteradores. E std::string{32,'*'}[0] == ' '(para ASCII). Mas tudo isso é verdade desde o C ++ 11.
Arne Vogel de
2
o que acontece com o parâmetro do vetor alocador? o que aconteceria se o parâmetro do vetor alocador não tivesse um argumento padrão? (você não pode deduzir do InputIterator)
gnzlbg
@NicolBolas: Você se importaria de explicar os detalhes de como os guias de dedução implícitos e explícitos podem funcionar no contexto de classes parcial ou totalmente especializadas (cujos construtores claramente não precisam ter tipos de parâmetros correspondentes aos do modelo primário)? É difícil encontrar informações sobre isso por meio de uma pesquisa rápida.
user541686
1
@NicolBolas: Entendo. Não está claro para mim se a pergunta é sobre guias de dedução explícitos ... Acho que é útil se você apenas incluir o que literalmente escreveu neste comentário.
user541686