Última atualização:2026-10-12
Dedução de argumentos de template de classe CTAD no C++17¶
Introdução¶
A metaprogramação de templates em C++ sempre foi uma funcionalidade bem conhecida dos desenvolvedores C++: tanto iniciantes quanto desenvolvedores avançados podem escrever código genérico com parâmetros de tipo por meio dela. Com a dedução de argumentos de template de classe (CTAD) introduzida no C++17, o trabalho com templates de classe tornou-se mais intuitivo e flexível.
Todo o código desta seção também será atualizado na comunidade.
O C++17, ao introduzir o CTAD, traz os seguintes benefícios:
Por exemplo: um código tão complexo quanto este
precisa apenas de:
Ou ainda, por exemplo:
pode ser simplificado para:
Portanto, vamos conhecer o CTAD hoje.
CTAD é a abreviação de Class template argument deduction, dedução de argumentos de template de classe; basta você fornecer ao compilador um deduction guide (guia de dedução) e já poderemos usar esse recurso.
Se não fornecermos, como no exemplo abaixo:
#include <iostream>
template <typename T, typename U>
struct MyPair {
T first{};
U second{};
};
int main() {
MyPair<int, int> p1{1, 2};
MyPair p2{1, 2};
std::cout << p1.first << ", " << p1.second << std::endl;
std::cout << p2.first << ", " << p2.second << std::endl;
return 0;
}
Para p2, obteríamos o erro:
no viable constructor or deduction guide for deduction of template arguments of 'MyPair'
E como corrigir isso?
Basta adicionar um deduction guide, escrevendo da seguinte forma:
A dedução de argumentos de template de classe (CTAD) simplifica a instanciação de templates de classe ao permitir que o compilador deduza os argumentos de template a partir dos argumentos do construtor. Antes da introdução do CTAD, os desenvolvedores tinham de especificar explicitamente os argumentos de template na instanciação. Com o CTAD, essa especificação explícita deixa de ser necessária, tornando o código mais legível e fácil de manter.
template <typename T>
class Add{
private:
T first;
T second;
public:
Add() = default;
Add(T first, T second): first_{first}, second_{second} {}
T result() const { return first + second; }
};
int main(){
Add one(1,2); // T被推导为int
Add two{1.245, 3.1415}; // T被推导为double
Add three = {0.24f, 0.34f}; // T被推导为float
}
No exemplo acima, o CTAD permite que o tipo T seja deduzido com base nos argumentos do construtor, eliminando a necessidade de especificação explícita de tipo.
Inicialização de membros não estáticos¶
Porém, há um cenário em que o CTAD não pode ser usado: a inicialização de membros não estáticos. Por exemplo: na classe Test, para usar o MyPair de fora, é preciso escrever o tipo completo.
template <typename T = int, typename U = int>
struct MyPair {
T first{};
U second{};
};
template <typename T, typename U>
MyPair(T, U) -> MyPair<T, U>;
class Test {
MyPair p4; // use of class template 'MyPair' requires template arguments; argument
// deduction not allowed in non-static class member
};
No exemplo acima, definimos uma classe de template MyPair e usamos CTAD nela. Contudo, quando tentamos usar MyPair como membro não estático da classe Test, por se tratar do contexto de inicialização de membro não estático, o CTAD não funciona, gerando um erro de compilação. Nesse caso, devemos especificar explicitamente os argumentos de template de MyPair.
Podemos ver que, no contexto de inicialização de membros não estáticos, o CTAD não consegue deduzir os argumentos de template. Portanto, quando um template de classe é usado como membro não estático, o desenvolvedor precisa especificar explicitamente todos os argumentos de template. Esse ponto merece atenção especial no desenvolvimento real, para garantir a corretude e a manutenibilidade do código.
Tópicos relacionados¶
- Atributo [[nodiscard]] no C++17 | C++那些事
- C++17 std::string_view | C++那些事
- Recursos de memória PMR no C++17 | C++那些事
- Dezessete funcionalidades avançadas do C++17 | C++那些事
- C++17 optional_ref | C++那些事
- C++17 std::variant | C++那些事
- Vinculações estruturadas no C++17 | C++那些事
- Dedução com auto em templates no C++17 | C++那些事
- Templates de variável no C++17 | C++那些事