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 imprimir Ponteiro para: seguido do valor apontado.
  • O main deve chamar a função com int, double e int*.
  • 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

  1. O template genérico imprimir(T valor) aceita qualquer tipo e imprime Valor: seguido do valor.
  2. A especialização imprimir(T* ptr) é uma sobrecarga mais específica para ponteiros. Ela será escolhida quando o argumento for um ponteiro.
  3. No main, declaramos int x = 42, double y = 3.14 e int z = 99.
  4. imprimir(x) deduz T = int e chama o template genérico.
  5. imprimir(y) deduz T = double e chama o template genérico.
  6. imprimir(&z) passa um int*. O compilador tenta deduzir T para o template genérico, mas a especialização para T* é 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 << ptr imprime 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