Médio C++
Especialização para ponteiros
Enunciado
Crie um template de função imprimir que exibe um valor na tela. Para tipos genéricos, imprima Valor: <valor>. Especialize o template para ponteiros (T*) de modo que imprima Ponteiro para: <valor apontado>. No main, chame imprimir com um int, um double e um int*.
Requisitos
- O template genérico deve imprimir
Valor:seguido do valor. - A especialização para
T*deve imprimirPonteiro para:seguido do valor apontado. - O
maindeve chamar a função comint,doubleeint*. - A saída deve corresponder exatamente ao esperado.
Código inicial
#include <iostream>
// TODO: template genérico imprimir
// TODO: especialização para T*
int main() {
// TODO: chame imprimir com int, double e int*
return 0;
}
Saída esperada
Valor: 42
Valor: 3.14
Ponteiro para: 99
Ver dica
A especialização para ponteiros é declarada como template<typename T> void imprimir(T* p). Dentro dela, imprima *p.
Mostrar solução
#include <iostream>
// Template genérico: imprime qualquer valor
template<typename T>
void imprimir(T valor) {
std::cout << "Valor: " << valor << '\n';
}
// Especialização para ponteiros: imprime o valor apontado
template<typename T>
void imprimir(T* ptr) {
std::cout << "Ponteiro para: " << *ptr << '\n';
}
int main() {
int x = 42;
double y = 3.14;
int z = 99;
imprimir(x); // T = int
imprimir(y); // T = double
imprimir(&z); // T = int, chama a especialização para T*
return 0;
}
Passo a passo
- O template genérico
imprimir(T valor)aceita qualquer tipo e imprimeValor:seguido do valor. - A especialização
imprimir(T* ptr)é uma sobrecarga mais específica para ponteiros. Ela será escolhida quando o argumento for um ponteiro. - No
main, declaramosint x = 42,double y = 3.14eint z = 99. imprimir(x)deduzT = inte chama o template genérico.imprimir(y)deduzT = doublee chama o template genérico.imprimir(&z)passa umint*. O compilador tenta deduzirTpara o template genérico, mas a especialização paraT*é mais específica e é escolhida, imprimindo o valor apontado.
Por que funciona
A especialização de template permite fornecer uma implementação diferente para um padrão de tipo, como ponteiros. O compilador compara as candidatas e escolhe a mais especializada. Neste caso, T* é mais específico que T, então a versão para ponteiros vence. Isso é útil para tratar ponteiros de forma segura, evitando imprimir endereços de memória acidentalmente.
Erros comuns
- Esquecer o
*na especialização:template<typename T> void imprimir(T ptr)não é uma especialização para ponteiros, mas sim outro template genérico. O compilador pode não saber qual escolher. - Não desreferenciar o ponteiro:
std::cout << ptrimprime o endereço, não o valor. Use*ptr. - Passar um ponteiro nulo: a desreferenciação causa comportamento indefinido. Verifique
if (ptr)antes de usar*ptr.
Outra forma de resolver
Se quiser evitar especialização, pode usar if constexpr (C++17) para detectar ponteiros:
template<typename T>
void imprimir(T valor) {
if constexpr (std::is_pointer_v<T>)
std::cout << "Ponteiro para: " << *valor << '\n';
else
std::cout << "Valor: " << valor << '\n';
}
Isso centraliza a lógica em uma única função, mas exige <type_traits>.
Saída esperada
Valor: 42
Valor: 3.14
Ponteiro para: 99