Domanda

Ho una classe visitatore simile a questa:

struct Visitor 
{
    template <typename T>
    void operator()(T t)
    {
        ...
    }

    void operator()(bool b)
    {
        ...
    }
};

Chiaramente, operator()(bool b) è inteso come una specializzazione della funzione modello precedente.

Tuttavia, non ha il template<> sintassi che sono abituato a vedere prima, dichiarandola come specializzazione del modello.Ma compila.

È sicuro?È corretto?

È stato utile?

Soluzione

Il tuo codice non è una specializzazione del modello, ma piuttosto una funzione non sumffata. Ci sono alcune differenze lì. L'operatore non TEMPLATO () avrà la precedenza su una versione modello (per una corrispondenza esatta, ma le conversioni di tipo non avranno luogo lì) ma puoi comunque forzare la funzione modello di essere chiamata:

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
}

Nel tuo codice non c'è molta differenza, ma se il tuo codice deve passare il tipo di parametro modello diventerà più divertente:

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
}

Altri suggerimenti

Quello che hai qui è il sovraccarico di funzioni; Per ottenere la specializzazione dei modelli, è davvero necessario il template <> sintassi. Tuttavia, dovresti essere consapevole che questi due approcci, anche se possono sembrare identici, sono sottilmente diversi e anche il compilatore potrebbe perdersi quando si sceglie la funzione giusta da chiamare. Elencare tutti i casi possibili sarebbe un po 'troppo lungo per questa risposta, ma potresti voler controllare Herb Sutter Gotw #49 a questo proposito.

Oh, compilerà. Semplicemente non sarà una funzione modello. Avrai una normale funzione non tempicata anziché una specializzazione modello.

È sicuro e in realtà probabilmente anche quello che vuoi. Il modello dei visitatori viene normalmente implementato mediante sovraccarico. Modelli di funzione specializzati Non è davvero una buona idea comunque.

Quello che hai fatto non è la serializzazione del modello, ma il sovraccarico delle funzioni. È sicuro.

PS È difficile dire se è corretto o no, senza sapere cosa stai cercando di ottenere. Tieni presente che, indipendentemente dal modello o dalla funzione sovraccarica, l'operatore verrà scelto in tempo di compilazione. Se hai bisogno di una spedizione di runtime, è necessario il polimorfismo, non il sovraccarico. Bene, probabilmente lo sai comunque; nel caso in cui.

Hai

  • void operator()(bool b) Questa è funzione non modellata
  • template< typename T > void operator()(T t) che è un modello di base separato che sovraccarica quanto sopra

Potresti avere una specializzazione completa del secondo come in template<> void operator(int i) che verrebbe preso in considerazione solo quando void operator()(bool b) non corrispondeva.

La specializzazione del modello di base viene utilizzata per selezionare quale dei metodi del modello di base chiamare.Tuttavia nel tuo caso hai un metodo non basato su modello che verrà preso in considerazione per primo.

L'articolo Perché non specializzarsi nei modelli di funzioni? fornisce una spiegazione abbastanza buona di come viene selezionato il metodo.

In sintesi:

  1. Le funzioni non modello sono considerate per prime (questo è il tuo semplice operatore () (bool) sopra)
  2. Modelli di base di funzioni vengono controllati in secondo luogo (questa è la funzione modello), viene selezionata la base di base più specializzata e quindi se ha una specializzazione per i tipi esatti che viene utilizzata la specializzazione altrimenti il ​​modello di base viene utilizzato con i tipi "corretti" (vedi Spiegazione nell'articolo)

Esempio:

#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);
}

Ricevi chiamate a:

operator()(bool b)       <-- first non template method that matches
template <> void operator()(int i)     <-- the most specialized specialization of templated function is called
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top