2012-02-16 4 views
7

Zacznę przepraszać, jeśli jestem na tyle głupia, aby nie znaleźć odpowiedzi, jeśli jest to tak oczywiste.C++: Jak zapobiec specjalizacji wskaźnika przez szablon?

Widziałem dziesiątki stron mówiących o specjalnej specjalizacji szablonów dla parametrów wskaźnik.

Chciałbym jednak móc uniemożliwić szablonowi specjalizację parametrów wskaźnika, ale nie mogę wymyślić, jak to zrobić.

template< class T > 
void function(T arg) 
{ 
    //... 
} 

int main() 
{ 
    int i = 42; 

    function(i); // Ok 
    function(&i); // Die bastart with a compiler error! 
} 

Czy to możliwe?

Dzięki.

+1

Kiedy masz dostęp do C++ 11, możesz po prostu użyć static_assert – PlasmaHH

+1

Czy nie powinien to być 'szablon '? – Jacob

+0

@Jacob: naprawiono teraz. – MSalters

Odpowiedz

14

Można zadeklarować specjalizacji (w tym przypadku jest to technicznie tylko przeciążenie), ale nie definiują go :)

template<typename T > 
void function(T arg) 
{ 
//... 
} 

template<typename T > 
void function(T* arg); //no definition 

int main() 
{ 
    int i = 42; 
    function(i); // Ok 
    function(&i); //ERROR 
} 
+0

Czy jest to błąd łącznika lub błąd kompilacji? –

+4

@ daknøk: To błąd kompilatora, ponieważ jest to szablon. Definicja szablonu powinna znajdować się w tej samej jednostce tłumaczeniowej (pliku źródłowym). Linker nic nie wie o szablonach. Kompilator jest odpowiedzialny za tworzenie szablonów i nie może tego zrobić bez definicji –

+0

+1 Hah, oczywiście, że łatwo! Dlaczego zawsze chcę robić to na własnej skórze? –

6

jestem sam szablon metaprogramowanie żółtodziobem, ale myślę

template<typename T> 
void function(typename std::enable_if<!std::is_pointer<T>::value,T>::type arg) 
{ 
    //... 
} 

powinien działać, ponieważ ta funkcja powinna istnieć tylko dla parametrów innych niż wskaźnik. Oczywiście wymaga to cech C++ 11 lub przynajmniej TR1 lub cech typu boost.

+0

+1 Testowałem alternatywę (do której jestem nieco bardziej przyzwyczajony): 'szablon nazwa_pliku enable_if :: wartość> :: funkcja typu (T arg)', ale twoja powinna również działać. (I oba powodują błędy * kompilatora *, a nie linker) –

7

w C++ 11, można użyć static_assert w sposób jak poniżej:

template<class T> 
void func(T arg) { 
    static_assert(!std::is_pointer<T>::value, 
       "The argument to func must not be a pointer."); 
    // Do something after the static_assert. 
    // Now you are sure that T isn't a pointer. 
} 

Przykład można znaleźć here on Ideone.

Polecam to, ponieważ da więcej przydatnych komunikatów o błędach, gdy ktoś spróbuje wywołać twoją funkcję za pomocą wskaźnika (błędy linkera mogą być w tym przypadku bardzo mylące). Ponadto, błędy linkera nie pojawią się przed pojawieniem się powiązania.