2009-04-16 25 views
10

En C++, une spécialisation de modèle de fonction est supposée agir exactement comme une fonction normale. Cela signifie-t-il que je peux en faire un virtuel?Est-ce que la spécialisation d'un modèle de fonction est virtuelle?

Par exemple:

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 me donne l'erreur suivante:

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

+7

Beau message d'erreur! Peut-être le publier sur MS Connect, même si votre code n'est pas "légal", le message devrait être meilleur. – Lucero

+3

Je ne sais pas avec certitude, donc je ne poste pas cela comme une vraie réponse, mais je parie que ce n'est pas légal, puisque le vtable finirait par être différent dans différentes unités de compilation qui ont appelé la fonction avec différents types (ou n'a pas appelé du tout). – rmeador

+0

gcc donne une pléthore de messages d'erreur, en commençant par "testtemp.cpp: 4: erreur: spécialisation explicite dans la portée non-espace struct A" – veefu

Répondre

19

Belle erreur de compilation. Pour ce type de vérifications, je me replie toujours sur le compilateur Comeau avant de revenir à la norme et de vérifier.

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(); ^

Maintenant, comme il a été posté par un autre utilisateur, le fait est que la norme ne vous permet pas de définir des méthodes virtuelles templated. La logique est que pour toutes les méthodes virtuelles, une entrée doit être réservée dans le vtable. Le problème est que les méthodes de modèle ne seront définies que lorsqu'elles auront été instanciées (utilisées). Cela signifie que le vtable finirait par avoir un nombre différent d'éléments dans chaque unité de compilation, en fonction du nombre d'appels différents à f() avec différents types se produisent. Puis l'enfer serait soulevée ...

Si ce que vous voulez est une fonction sur l'un basé sur un modèle ses arguments et une version spécifique étant virtuelle (note de la part de l'argument), vous pouvez le faire:

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" 
} 

Si vous voulez généraliser cela pour n'importe quel type, alors vous n'avez pas de chance. Considérons un autre type de délégation à la place du polymorphisme (l'agrégation + délégation pourrait être une solution). Plus d'informations sur le problème à portée de main aideraient à déterminer une solution.

+2

s'il vous plaît noter un appel à b.f (5); va générer une spécialisation qui n'est pas virtuelle et l'appeler. Comme vous avez surchargé le modèle avec un non-modèle, un appel préférera le non-modèle. mais si vous appelez b.f (5); il appellera toujours une fonction non-virtuelle. –

+1

qui a dit, bien sûr, la surcharge est la voie à suivre ici. en fait, dans le livre "C++ standards de codage", une règle est d'éviter la spécialisation explicite du template de fonction, car elle est limitée et la surcharge fournit une alternative supérieure. –

+0

J'essaie de définir une fonction GetValue qui retournera une valeur de type T. T provient toujours d'un ensemble connu de types. Je veux être capable d'appeler la fonction à partir de modèles sans avoir à donner un nom différent à chaque version. – alexk7

1

Comme d'autres l'ont noté, ce code n'est pas légal car un modèle de fonction membre ne peut pas être déclaré virtual.

Pourtant, même Visual Studio 2012 selfs sur ce point: C++ internal compiler error on Visual Studio 2012 Click here for full size

journaux d'événements indiquent que le compilateur est écrasé sur 0xC0000005 ou STATUS_ACCESS_VIOLATION. C'est marrant comment une certaine construction de code (illégale) peut rendre le segfault du compilateur ...