Resumo executivo: não faça isso.
A resposta de j_random_hacker diz como fazer isso. No entanto, também gostaria de salientar que você não deve fazer isso. O ponto principal dos modelos é que eles podem aceitar qualquer tipo compatível, e as restrições de tipo de estilo Java quebram isso.
As restrições de tipo do Java são um bug, não um recurso. Eles estão lá porque o Java digita apagamento em genéricos, portanto, o Java não consegue descobrir como chamar métodos com base apenas no valor dos parâmetros de tipo.
C ++, por outro lado, não tem essa restrição. Os tipos de parâmetro do modelo podem ser de qualquer tipo compatível com as operações com as quais são usados. Não precisa haver uma classe base comum. Isso é semelhante ao "Duck Typing" do Python, mas feito em tempo de compilação.
Um exemplo simples mostrando o poder dos modelos:
// Sum a vector of some type.
// Example:
// int total = sum({1,2,3,4,5});
template <typename T>
T sum(const vector<T>& vec) {
T total = T();
for (const T& x : vec) {
total += x;
}
return total;
}
Essa função de soma pode somar um vetor de qualquer tipo que suporte as operações corretas. Ele funciona com ambas as primitivas, como int / long / float / double, e tipos numéricos definidos pelo usuário que sobrecarregam o operador + =. Heck, você pode até usar esta função para juntar strings, já que elas suportam + =.
Nenhum boxe / unboxing de primitivos é necessário.
Observe que ele também constrói novas instâncias de T usando T (). Isso é trivial no C ++ usando interfaces implícitas, mas não é realmente possível em Java com restrições de tipo.
Embora os modelos C ++ não tenham restrições de tipo explícitas, eles ainda são do tipo seguro e não serão compilados com código que não suporta as operações corretas.