2012-01-13 14 views
11

Próbuję zrobić, aby moja funkcja szablonu generowała błąd podczas kompilacji, jeśli instancja nie specjalistyczna zostanie utworzona. Próbowałem zwykłego wzorca assert w czasie kompilacji (ujemny rozmiar tablicy), ale kompilacja nie działa, nawet jeśli szablon nie jest instancjonowany. Wszelkie przemyślenia na temat tego, jak sprawić, aby to się nie udało, tylko wtedy, gdy zostanie utworzona funkcja szablonu podstawowego?Jak wymusić stosowanie specjalizacji szablonów?

template<class Foo> void func(Foo x) { 
    // I want the compiler to complain only if this function is instantiated. 
    // Instead, the compiler is complaining here at the declaration. 
    int Must_Use_Specialization[-1]; 
} 

template<> void func(int x) { 
    printf("Hi\n"); 
} 

Odpowiedz

1

Wystarczy użyć Boost.StaticAssert

(edycja: lub static_assert jeśli masz 11 wsparcie C++ zapomniałem o tym.).

+1

Powinien to być po prostu 'static_assert' (słowo kluczowe, a nie funkcja biblioteki). – UncleBens

+0

Poprawione, dziękuję! – Useless

17

Nie definiowania jest najprostszym rozwiązaniem:

template<class Foo> void func(Foo x); 

template<> void func(int x) { 
    printf("Hi\n"); 
} 

Można również zdefiniować je w plikach CPP i use this która będzie działać.

i statyczne metody assert:

template<class Foo> void func(Foo x) { 
    static_assert(sizeof(Foo) != sizeof(Foo), "func must be specialized for this type!"); 
} 
+2

bym zmienić wiadomość do '„func musi być specjalnie przystosowane do tego typu!”' Wyjaśnienia –

+0

myślałem o inny sposób, który działa. Tylko odwołanie do nieistniejącego elementu klasy jest funkcją podstawową. – drwowe

5

trzeba uzależnić od Foo, tak:

int Must_Use_Specialization[-sizeof(Foo)]; 
6

w C++ 11 można użyć static_assert tak:

template<typename T> struct fake_dependency: public std::false_type {}; 
template<class Foo> void func(Foo x) { 
    static_assert(fake_dependency<Foo>::value, "must use specialization"); 
} 

Konstrukcja fake_dependency jest niezbędna do uzależnienia dowodu na swoim parametrze szablonu, więc czeka z oceną, aż do utworzenia instancji szablonu. Można podobnie naprawić swoje rozwiązanie tak:

template<class> struct fake_dependency { enum {value = -1 }; }; 

template<class Foo> void func(Foo x) { 
    int Must_Use_Specialization[fake_dependency<Foo>::value]; 
} 

Zobacz także here for a live demo.

+0

To działa. Myślałem także o innych rozwiązaniach, które działają: odwołując się do nieistniejącego elementu, więc podstawową funkcją staje się: szablon void func (Foo x) { x.You_must_call_a_specialization_of_this_function; } – drwowe

+0

@ user1148117: podany nieskończona liczba możliwych klas, trudno jest zagwarantować pewne Foo nie będzie miał tego członka :) – UncleBens

+0

Innym sposobem tworzenia dependecy we wzorcowym argumentu bez konieczności tworzenia dodatkowego rodzaju jest użycie 'static_assert (sizeof (T) == 0," ... ");'. To działa, ponieważ norma określa, że ​​każdy rodzaj (nawet pustych kodowanym) mają rozmiar co najmniej 1. Zauważ, że niektóre kompilatory pozwalają rodzajów 0 długości w postaci rozszerzenia języka (np GCC [ „Struktury bez żadnych Członków”] (https : //gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Empty-Structures.html)). –

3

Nie potrzebujesz szablonu bazowego, jeśli nigdy go nie użyjesz! Po prostu dostarcz przeciążenia dla typów, które chcesz użyć!

void func(int x) { 
    printf("Hi 1\n"); 
} 

void func(double x) { 
    printf("Hi 2\n"); 
} 

void func(Bar x) { 
    printf("Hi 3\n"); 
} 

To będzie Ci się błąd czasu kompilacji dla func(foo); (chyba foo jest zamienny do jednego z innych typów).

+0

+1 za preferowanie przeciążania do specjalizacji funkcji szablonu! – AJG85

Powiązane problemy