2009-04-16 14 views
10

W C++ specjalizacja szablonu funkcji ma działać dokładnie tak, jak normalna funkcja. Czy to oznacza, że ​​mogę zrobić jeden wirtualny?Czy tworzenie specjalizacji szablonów funkcji jest legalne?

Na przykład:

struct A 
{ 
    template <class T> void f(); 
    template <> virtual void f<int>() {} 
}; 

struct B : A 
{ 
    template <class T> void f(); 
    template <> virtual void f<int>() {} 
}; 

int main(int argc, char* argv[]) 
{ 
    B b; 
    A& a = b; 
    a.f<int>(); 
} 

Visual Studio 2005 daje mi następujący błąd:

fatal error C1001: An internal error has occurred in the compiler.

+7

Przyjemny komunikat o błędzie! Może po przesłaniu go do MS Connect, nawet jeśli twój kod nie jest "legalny", wiadomość powinna być lepsza. – Lucero

+3

Nie wiem na pewno, więc nie uważam tego za prawdziwą odpowiedź, ale założę się, że nie jest to legalne, ponieważ vtable byłby inny w różnych jednostkach kompilacji, które nazywałyby funkcję z różnymi typy (lub w ogóle tego nie nazywały). – rmeador

+0

gcc daje mnóstwo komunikatów o błędach, zaczynając od "testtemp.cpp: 4: błąd: jawna specjalizacja w zakresie przestrzeni nazw" struct A "" – veefu

Odpowiedz

19

Dobry błąd kompilatora. W przypadku tego typu sprawdzeń zawsze wracam do kompilatora Comeau przed powrotem do standardu i sprawdzeniem.

Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2 Copyright 1988-2008 Comeau Computing. All rights reserved. MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 3: error: "virtual" is not allowed in a function template declaration template virtual void f(); ^

"ComeauTest.c", line 10: error: "virtual" is not allowed in a function template declaration template virtual void f(); ^

Teraz, ponieważ został opublikowany przez innego użytkownika, faktem jest, że standard nie pozwala na definiowanie wirtualnych metod szablonowych. Uzasadnieniem jest to, że dla wszystkich metod wirtualnych wpis musi być zarezerwowany w vtable. Problem polega na tym, że metody szablonów zostaną zdefiniowane dopiero po ich utworzeniu (użyciu). Oznacza to, że vtable będzie miał inną liczbę elementów w każdej jednostce kompilacji, w zależności od tego, ile różnych wywołań do f() z różnych typów się zdarzyć. Następnie cholery będzie podniesiony ...

Jeśli to, co chcesz jest na matrycy funkcji na jednym ze swoich argumentów i jednego konkretnego wersja jest wirtualny (zauważ część argumentu) można to zrobić:

class Base 
{ 
public: 
    template <typename T> void f(T a) {} 
    virtual void f(int a) { std::cout << "base" << std::endl; } 
}; 
class Derived : public Base 
{ 
public: 
    virtual void f(int a) { std::cout << "derived" << std::endl; } 
}; 
int main() 
{ 
    Derived d; 
    Base& b = d; 
    b.f(5); // The compiler will prefer the non-templated method and print "derived" 
} 

Jeśli chcesz to uogólnić dla dowolnego typu, to masz pecha. Rozważmy inny rodzaj delegacji zamiast polimorfizmu (rozwiązaniem może być agregacja + delegacja). Więcej informacji na temat problemu może pomóc w określeniu rozwiązania.

+2

proszę zwrócić uwagę na połączenie z b.f (5); wygeneruje specjalizację, która nie jest wirtualna i wywołaj ją. Ponieważ przeładowałeś szablon bez szablonu, połączenie będzie preferować szablon inny niż szablon. ale jeśli zadzwonisz pod numer b.f (5); nadal będzie wywoływać funkcję inną niż wirtualna. –

+1

powiedziawszy, oczywiście przeciążenie to sposób, aby przejść tutaj. w rzeczywistości, w książce "Standardy kodowania C++", jedna zasada polega na unikaniu jawnej specjalizacji szablonu funkcji, ponieważ jest ograniczona, a przeciążanie zapewnia lepszą alternatywę. –

+0

Próbuję zdefiniować funkcję GetValue, która zwróci wartość typu T. T jest zawsze ze znanego zestawu typów. Chcę móc wywoływać funkcję z szablonów bez konieczności nadawania każdej wersji innej nazwy. – alexk7

1

Jak zauważyli inni, nie jest to prawny kod, ponieważ nie można oznaczyć szablonu funkcji członka jako virtual.

Jednak nawet Visual Studio 2012 dławiki na to: C++ internal compiler error on Visual Studio 2012 Click here for full size

Dzienniki zdarzeń wskazuje, że kompilator rozbił się na 0xC0000005 lub STATUS_ACCESS_VIOLATION. To zabawne, jak pewna (nielegalna) konstrukcja kodu może spowodować uszkodzenie kompilatora ...

Powiązane problemy