2009-04-20 20 views
8

Próbuję zaimplementować funkcję szablonu z uchwytami unieważniającymi inaczej przy użyciu specjalizacji szablonu.Specjalizacja szablonu dla statycznych funkcji składowych; jak?

Poniższy kod daje mi „Explicit specjalizacji w zakresie non-namespace” w gcc:

template <typename T> 
static T safeGuiCall(boost::function<T()> _f) 
{ 
    if (_f.empty()) 
     throw GuiException("Function pointer empty"); 
    { 
     ThreadGuard g; 
     T ret = _f(); 
     return ret; 
    } 
} 

// template specialization for functions wit no return value 
template <> 
static void safeGuiCall<void>(boost::function<void()> _f) 
{ 
    if (_f.empty()) 
     throw GuiException("Function pointer empty"); 
    { 
     ThreadGuard g; 
     _f(); 
    } 
} 

Próbowałem przesuwając go z klasy (klasa nie jest na matrycy) oraz w przestrzeni nazw, ale wtedy pojawia się błąd "Wyraźna specjalizacja nie może mieć klasy pamięci". Czytałem wiele dyskusji na ten temat, ale ludzie nie zgadzają się, jak specjalizować szablony funkcji. Jakieś pomysły?

Odpowiedz

12

Kiedy specjalizują metodę szablonie, należy to zrobić poza nawiasami klasy:

template <typename X> struct Test {}; // to simulate type dependency 

struct X // class declaration: only generic 
{ 
    template <typename T> 
    static void f(Test<T>); 
}; 

// template definition: 
template <typename T> 
void X::f(Test<T>) { 
    std::cout << "generic" << std::endl; 
} 
template <> 
inline void X::f<void>(Test<void>) { 
    std::cout << "specific" << std::endl; 
} 

int main() 
{ 
    Test<int> ti; 
    Test<void> tv; 
    X::f(ti); // prints 'generic' 
    X::f(tv); // prints 'specific' 
} 

Jeśli wziąć ją na zewnątrz klasy, trzeba usunąć słowo kluczowe "statyczne". Statyczne słowo kluczowe poza klasą ma określone znaczenie inne niż prawdopodobnie.

template <typename X> struct Test {}; // to simulate type dependency 

template <typename T> 
void f(Test<T>) { 
    std::cout << "generic" << std::endl; 
} 
template <> 
void f<void>(Test<void>) { 
    std::cout << "specific" << std::endl; 
} 

int main() 
{ 
    Test<int> ti; 
    Test<void> tv; 
    f(ti); // prints 'generic' 
    f(tv); // prints 'specific' 
} 
+0

hm Próbowałem już tego samego, ale umieść go w pliku .hpp i próbowałem go włączyć ... potem pojawia się błąd "wielokrotna definicja vodi X: ff (Test ) .Nie widzę, co by być różnica? – Rolle

+1

Czy był to błąd kompilatora lub linkera?Jeśli był to błąd kompilatora, oznacza to, że prawdopodobnie zawiera on nagłówek szablonu więcej niż jeden raz i brakuje osłon nagłówka, a tym samym podwójną definicję: kompilator widzi dwie (niestety dokładnie dokładne) definicje dla implementacji. –

+0

Dlaczego powinienem dodać wbudowany pierwszy przypadek? Jeśli nie, otrzymuję błąd kompilacji. – sop

3

Można zadeklarować wyraźnej specjalizacji w taki sam sposób chcesz zdefiniować funkcję składową poza jego klasę:

class A 
{ 
public: 
    template <typename T> 
    static void foo() {} 
}; 

template <> 
void A::foo<void>() 
{ 
} 
+0

Dzięki za odpowiedź. Dla mnie nie ma znaczenia, czy są w klasie, czy nie; ale nie mogę sprawić, żeby działało tak czy inaczej. Czy moja składnia jest zła, czy coś w tym kodzie, który podałem? – Rolle

+0

Chodzi o to, że jawnie wyspecjalizowałeś funkcję w przestrzeni nazw za pomocą kwalifikowanego deklaratora funkcji. C++ nie pozwala na ponowne dodanie "statycznego" słowa kluczowego, więc po prostu go usunąć. Mój przykład powyżej pokazuje, jak jawnie specjalizować statycznego członka. –

2

Twój problem wydaje się być z boost :: funkcji - następujące specjalizacje pracy:

+0

Przepraszam, wypróbowałem to, ale nie działa. Czy skompilowałeś pod GCC? Myślę, że działa pod VS na przykład ... – Rolle

+0

To jest g ++ wersja 3.4.5 –

+0

To jest statyka - usuń je i wszystko powinno być cienkie, kompiluje się z comeau, zaktualizuję odpowiedź –

4

to nie bezpośrednio odpowiedzi na swoje pytanie, ale można napisać ten

template <typename T> 
static T safeGuiCall(boost::function<T()> _f) 
{ 
     if (_f.empty()) 
       throw GuiException("Function pointer empty"); 
     { 
       ThreadGuard g; 
       return _f(); 
     } 
} 

Powinno działać, nawet jeśli _f() zwróci 'void'

Edycja: w bardziej ogólnym przypadku, myślę, że powinniśmy preferować przeciążanie funkcji zamiast specjalizacji. Tutaj jest dobrym wyjaśnieniem tego: http://www.gotw.ca/publications/mill17.htm

+1

tak bardzo dobrze punkt –

+0

I Jestem pewien, że to nie zadziała. T nie jest nigdzie zdefiniowane? – Rolle

+0

@Rolle Sorry "template " nie przetrwał do skopiowania/wklejenia. – Rexxar

1

Miałem podobny problem. Jeśli spojrzysz na oryginalny post, zostawiłem pierwsze statyczne, ale wyjąłem drugie i zniknęły BOTH.

Powiązane problemy