2009-06-01 23 views
8

Mam klasy odwiedzających przypominający ten:Czy specjalizacja szablonów wymaga szablonu <>?

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

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

Najwyraźniej operator()(bool b) jest przeznaczony do specjalizacji z poprzednim funkcji szablonu.

Jednak nie ma ona składni, którą widziałem wcześniej, uznając to za szablon specjalizacji. Ale to się kompiluje.

Czy to jest bezpieczne? Czy to jest poprawne?

Odpowiedz

19

Twój kod nie jest szablonową specjalizacją, ale raczej niesformatowaną funkcją. Tam są pewne różnice. Operator bez matrycy() będzie mieć pierwszeństwo nad matrycy wersji (na dokładne dopasowanie, ale typ konwersji nie odbędzie się tam), ale nadal można zmusić funkcję matrycy na miano:

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 
} 

w twojej Kod nie ma wielkiej różnicy, ale jeśli Twój kod musi przejść typ parametru szablonu będzie się śmieszniejsze:

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 
} 
+0

Wierzę, że "szablon <> void operator() (dane int) {" w sekcji kodu najwyższego powinien być "szablon <> void operator() (dane int) {", a w sekcji dolnej, "int g() {"powinno być" int () {"na dole (przepraszam, nie wiem jak stylizować sekcje kodu w komentarzach) –

+0

Miałem wątpliwości, ale zarówno kompilatory GCC, jak i Comeau'a przyjmują kod jako ważny. Nie mogę przetestować MSVS teraz, jeśli możesz spróbować, byłbym wdzięczny :) –

+0

nadal zajrzyj do odpowiedzi tutaj http://stackoverflow.com/questions/937744/function-template-specialization-format – stefanB

4

Och, to się skompiluje. To po prostu nie będzie funkcją szablonu. Będziesz miał regularną funkcję bez szablonu zamiast specjalizacji szablonu.

Jest to bezpieczne, a nawet najbardziej prawdopodobne, co chcesz. Wzór użytkownika jest zwykle implementowany przez przeciążenie. Specjalizujące szablony funkcji isn't really a good idea anyway.

+0

Czy istnieją sytuacje, w których byłoby to zachowują się inaczej? Czy jest to potencjalny błąd, czy po prostu zły styl? –

+0

Zazwyczaj jest to słuszne. Powinieneś zazwyczaj preferować zwykłe przeciążenia w porównaniu ze specjalizacjami szablonów funkcji. Zachowanie jest bardziej przewidywalne. – jalf

+0

+1 za link, dokładnie to, czego szukałem. – avakar

2

To co zrobiłeś, to nie serializacja szablonów, ale przeciążanie funkcji. To jest bezpieczne.

P.S. Trudno powiedzieć, czy to prawda, czy nie, nie wiedząc, co chcesz osiągnąć. Należy pamiętać, że niezależnie od tego, czy jest to szablon, czy przeciążona funkcja, operator zostanie wybrany podczas kompilacji. Jeśli potrzebujesz uruchomienia w czasie, potrzebujesz polimorfizmu, a nie przeciążania. Cóż, prawdopodobnie i tak o tym wiesz; w razie czego.

5

To, co tu masz, to przeciążanie funkcji; aby uzyskać specjalizację szablonów, rzeczywiście potrzebujesz składni template <>. Należy jednak pamiętać, że te dwa podejścia, nawet jeśli wydają się identyczne, są nieco różne, a nawet kompilator może się zagubić, wybierając odpowiednią funkcję do wywoływania. Lista wszystkich możliwych przypadków byłaby zbyt długa na tę odpowiedź, ale możesz chcieć sprawdzić Herb Sutter GoTW #49 na ten temat.

2

masz

  • void operator()(bool b) który jest non matrycy funkcja
  • template< typename T > void operator()(T t) który jest oddzielnym szablon baza że przeciąża powyżej

Można mieć pełną specjalizację drugiego jak w template<> void operator(int i) które byłyby uznane tylko wtedy, gdy void operator()(bool b) nie pasuje.

Specjalizacja szablonu bazowego służy do wyboru, która z podstawowych metod szablonów ma zostać wywołana.Jednak w twoim przypadku masz niesformatowaną metodę, która zostanie rozpatrzona jako pierwsza.

Artykuł Why Not Specialize Function Templates? podaje całkiem dobre wyjaśnienie sposobu wyboru metody.

W sumary:

  1. Non funkcje szablonów są badanym pierwszy (jest to zwykły operator() (bool) powyżej)
  2. szablony bazowe Funkcja get sprawdzone sekundę (jest to Twoja matrycy funkcja), wybierany jest najbardziej wyspecjalizowany szablon bazowy, a następnie, jeśli ma specjalizację dla dokładnie tych typów, których specjalizacja jest używana, w przeciwnym razie szablon bazowy jest używany z "poprawnymi" typami (patrz wyjaśnienie w artykule)

Przykład:

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

uzyskać połączenia do:

operator()(bool b)  <-- first non template method that matches 
template <> void operator()(int i)  <-- the most specialized specialization of templated function is called 
+2

Tęsknisz za nawiasami argumentów: szablon <> void doh :: operator() <> (bool b) (zwróć uwagę na "<>" i wstawiony) i zauważ, że on (sutter) wyraźnie pisze, że najbardziej wyspecjalizowany szablon bazowy jest zaznaczona. Nie "ten o najbardziej dopasowanej specjalizacji" ani "najbardziej wyspecjalizowana specjalizacja funkcji szablonowej". Rozdzielczość jawnie uwzględnia tylko szablony podstawowe (podstawowe). Nazywa się to "częściowym porządkowaniem szablonów funkcji" i jest opisane w standardzie 14.6.6.2. –

+0

Masz rację co do wyboru szablonów bazowych, myślę, że zwinąłem to moje wyjaśnienie (leniwe pisanie?), Próbowałem powiedzieć, że wybrano najbardziej wyspecjalizowany szablon bazowy, a następnie, jeśli ma on specjalizację dla dokładnych typów, które specjalizacja jest używana, w przeciwnym razie szablon bazowy jest używany z 'poprawnymi' typami – stefanB

+0

Na gcc3.3.3 oba z szablonem nawiasów <> void doh :: operator() <> (bool b) i bez szablonu formularza <> void doh :: operator() (bool b) kompilują i dały mi ten sam wynik, nadal kopiuj/wklej przykład przez @dribeas da błąd błędu: jawna specjalizacja w zakresie przestrzeni nazw 'struct doh 'itd. - to właśnie miałem na myśli (i ponieważ wszystkie metody są prywatne, ale to jest na marginesie) – stefanB

Powiązane problemy