As especializações de modelos requerem modelo <> sintaxe?
-
06-09-2019 - |
Pergunta
Eu tenho uma aula de visitante parecida com isso:
struct Visitor
{
template <typename T>
void operator()(T t)
{
...
}
void operator()(bool b)
{
...
}
};
Claramente, operator()(bool b)
pretende ser uma especialização da função do modelo anterior.
No entanto, não tem o template<>
Sintaxe que estou acostumada a ver antes, declarando isso como uma especialização em modelo. Mas isso compila.
Isso é seguro? Isso está correto?
Solução
Seu código não é uma especialização de modelo, mas uma função não templada. Existem algumas diferenças lá. O operador não templado () terá precedência sobre uma versão modelada (para uma correspondência exata, mas as conversões de tipo não ocorrerão lá), mas você ainda pode forçar a função modelada a ser chamada:
class Visitor
{
public: // corrected as pointed by stefanB, thanks
template <typename T>
void operator()( T data ) {
std::cout << "generic template" << std::endl;
}
void operator()( bool data ) {
std::cout << "regular member function" << std::endl;
}
};
template <> // Corrected: specialization is a new definition, not a declaration, thanks again stefanB
void Visitor::operator()( int data ) {
std::cout << "specialization" << std::endl;
}
int main()
{
Visitor v;
v( 5 ); // specialization
v( true ); // regular member function
v.operator()<bool>( true ); // generic template even if there is a non-templated overload
// operator() must be specified there (signature of the method) for the compiler to
// detect what part is a template. You cannot use <> right after a variable name
}
No seu código, não há muita diferença, mas se o seu código precisar passar no tipo de parâmetro do modelo, ele ficará mais engraçado:
template <typename T>
T g() {
return T();
}
template <>
int g() {
return 0;
}
int g() {
return 1;
}
int main()
{
g<double>(); // return 0.0
g<int>(); // return 0
g(); // return 1 -- non-templated functions take precedence over templated ones
}
Outras dicas
O que você tem aqui é sobrecarga de função; Para obter a especialização do modelo, você realmente precisa do template <>
sintaxe. No entanto, você deve estar ciente de que essas duas abordagens, mesmo que possam parecer idênticas, são sutilmente diferentes e até o compilador pode se perder ao escolher a função certa para chamar. Listar todos os casos possíveis seria um pouco longo demais para esta resposta, mas você pode querer verificar Herb Sutter Gotw #49 sobre o assunto.
Oh, vai compilar. Não será uma função de modelo. Você terá uma função regular não-templica em vez de uma especialização em modelo.
É seguro, e provavelmente o que você quer também. O padrão do visitante é normalmente implementado por sobrecarga. Modelos de função especializados Não é realmente uma boa ideia de qualquer maneira.
O que você fez não é a serialização do modelo, mas a sobrecarga de funcionamento. É seguro.
PS É difícil dizer se está correto ou não, sem saber o que você está tentando alcançar. Lembre -se de que não importa o modelo ou a função sobrecarregada, seu operador será escolhido no tempo de compilação. Se você precisar despacho de tempo de execução, precisará de polimorfismo, não sobrecarregar. Bem, você provavelmente sabe de qualquer maneira; apenas no caso de.
Você tem
void operator()(bool b)
isso é uma função não modificadatemplate< typename T > void operator()(T t)
que é um modelo base separado que sobrecarrega o acima
Você poderia ter uma especialização completa do segundo como em template<> void operator(int i)
o que só seria considerado quando void operator()(bool b)
não combinou.
A especialização do modelo base é usada para selecionar qual dos métodos de modelo base para chamar. No entanto, no seu caso, você possui um método não temperado que será considerado primeiro.
O artigo Por que não especializar modelos de função? fornece uma explicação bastante boa de como o método é selecionado.
Em Sumary:
- As funções não modelo são consideradas primeiro (este é o seu operador simples () (bool) acima)
- Os modelos de base da função são verificados em segundo (esta é a sua função modelo), o modelo de base mais especializado será selecionado e, se tiver especialização para os tipos exatos de que a especialização é usada, caso contrário, o modelo base é usado com os tipos 'corretos' (consulte Explicação no artigo)
Exemplo:
#include <iostream>
using namespace std;
struct doh
{
void operator()(bool b)
{
cout << "operator()(bool b)" << endl;
}
template< typename T > void operator()(T t)
{
cout << "template <typename T> void operator()(T t)" << endl;
}
};
// note can't specialize inline, have to declare outside of the class body
template<> void doh::operator()<>(int i)
{
cout << "template <> void operator()<>(int i)" << endl;
}
template<> void doh::operator()<>(bool b)
{
cout << "template <> void operator()<>(bool b)" << endl;
}
int main()
{
doh d;
int i;
bool b;
d(b);
d(i);
}
Você recebe ligações para:
operator()(bool b) <-- first non template method that matches
template <> void operator()(int i) <-- the most specialized specialization of templated function is called