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?

Foi útil?

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 modificada
  • template< 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:

  1. As funções não modelo são consideradas primeiro (este é o seu operador simples () (bool) acima)
  2. 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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top