Frage

Ich habe eine Besucherklasse, die dem ähnelt:

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

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

Deutlich, operator()(bool b) soll eine Spezialisierung der vorhergehenden Vorlagenfunktion sein.

Es hat jedoch nicht das template<> Syntax, an die ich es gewohnt bin, vorher zu sehen, und dies als Vorlagenspezialisierung deklariere. Aber es kompiliert.

Ist das sicher? Ist das richtig?

War es hilfreich?

Lösung

Ihr Code ist keine Vorlagenspezialisierung, sondern eine nicht templare Funktion. Es gibt einige Unterschiede dort. Der nicht templatte Operator () hat Vorrang vor einer Vorlagenversion (für eine genaue Übereinstimmung, aber dort werden Typumbauten stattfinden), aber Sie können trotzdem die zugenannte Vorlagenfunktion erzwingen:

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
}

In Ihrem Code gibt es keinen großen Unterschied, aber wenn Ihr Code den Vorlageparametertyp übergeben muss, wird er lustiger:

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
}

Andere Tipps

Was Sie hier haben, ist Funktion Überladen; Um die Vorlagenspezialisierung zu erhalten, benötigen Sie tatsächlich die template <> Syntax. Sie sollten sich jedoch bewusst sein, dass diese beiden Ansätze, auch wenn sie identisch erscheinen, subtil unterschiedlich sind, und selbst der Compiler kann sich bei der Auswahl der richtigen Funktion verlieren. Die Auflistung aller möglichen Fälle wäre für diese Antwort etwas zu lang, aber Sie möchten vielleicht überprüfen Herb Sutter Gotw #49 zum Thema.

Oh, es wird kompilieren. Es wird einfach keine Vorlagenfunktion sein. Sie haben eine regelmäßige Nicht-Template-Funktion anstelle einer Vorlagenspezialisierung.

Es ist sicher und wahrscheinlich auch das, was Sie auch wollen. Das Besuchermuster wird normalerweise durch Überlastung implementiert. Spezialisierungsfunktionsvorlagen Ist nicht wirklich eine gute Idee.

Was Sie getan haben, ist keine Vorlagenserialisierung, sondern die Funktion Überladung. Es ist sicher.

PS Es ist schwer zu sagen, ob es richtig ist oder nicht, ohne zu wissen, was Sie erreichen möchten. Denken Sie daran, dass Ihr Bediener egal, dass es Vorlage oder überlastete Funktion ist, in Kompilierungszeit ausgewählt wird. Wenn Sie den Versand von Laufzeit benötigen, benötigen Sie Polymorphismus, nicht überladen. Nun, du weißt es wahrscheinlich sowieso; Nur für den Fall.

Du hast

  • void operator()(bool b) Das ist nicht Vorlagenfunktion
  • template< typename T > void operator()(T t) Dies ist eine separate Basisvorlage, die die oben genannten überlastet

Sie könnten eine volle Spezialisierung des zweiten haben wie in template<> void operator(int i) das würde nur berücksichtigt werden, wenn void operator()(bool b) hat nicht gepasst.

Die Spezialisierung der Basisvorlage wird verwendet, um auszuwählen, welche der Basisvorlagenmethoden aufgerufen werden sollen. In Ihrem Fall haben Sie jedoch eine nicht templare Methode, die zuerst berücksichtigt wird.

Der Artikel Warum nicht spezialisierte Funktionsvorlagen? gibt eine recht gute Erklärung, wie die Methode ausgewählt wird.

In Sumary:

  1. Nicht -Vorlagenfunktionen werden zuerst betrachtet (dies ist Ihr einfacher Bediener () (bool) oben)
  2. Funktionsbasisvorlagen werden die zweite Überprüfung (dies ist Ihre Vorlagenfunktion), die spezialisierteste Basis-Template wird ausgewählt. Wenn sie dann für die genauen Typen spezifiziert wird, wird die Spezialisierung verwendet, da sonst die Basisvorlage mit "The Right" -Typen verwendet wird (siehe Erläuterung im Artikel)

Beispiel:

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

Sie erhalten Anrufe an:

operator()(bool b)       <-- first non template method that matches
template <> void operator()(int i)     <-- the most specialized specialization of templated function is called
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top