2008-10-08 22 views
11

J'ai une classe de modèle C++ qui est instanciée avec 3 paramètres de type différents. Il existe une méthode que la classe doit avoir pour un seul de ces types et qui n'est jamais appelée avec les deux autres types.Le code objet est-il généré pour les méthodes de classe de modèle inutilisées?

Le code objet de cette méthode sera-t-il généré trois fois (pour tous les types pour lesquels le modèle est instancié), ou le code objet est-il généré une seule fois (pour le type avec lequel il est réellement utilisé)?

Répondre

20

Les fonctions de membre virtuel sont instanciées lorsqu'un modèle de classe est instancié, mais les fonctions de membre non virtuelles sont instanciées uniquement si elles sont appelées.

Ceci est couvert par [temp.inst] dans la norme C++ (En C++ 11, c'est §14.7.1/10. En C++ 14, c'est §14.7.1/11, et en C++ 17 est §17.7.1/9. Extrait du 17 C++ ci-dessous)

une mise en œuvre ne doit pas instancier implicitement un modèle de fonction, un modèle variable, un modèle membre , un non virtuel fonction membre, une classe de membre, un membre de données statiques d'un modèle de classe, ou une sous-structure d'une instruction if constexpr (9.4.1), à moins que l'instanciation est nécessaire

Notez également qu'il est possible d'instancier un modèle de classe même si certaines des fonctions membres ne sont pas instanciables pour les paramètres de modèle donnés. Par exemple:

template <class T> 
class Xyzzy 
{ 
public: 
    void CallFoo() { t.foo(); } // Invoke T::foo() 
    void CallBar() { t.bar(); } // Invoke T::bar() 

private: 
    T t; 
}; 

class FooBar 
{ 
public: 
    void foo() { ... } 
    void bar() { ... } 
}; 

class BarOnly 
{ 
public: 
    void bar() { ... } 
}; 

int main(int argc, const char** argv) 
{ 
    Xyzzy<FooBar> foobar; // Xyzzy<FooBar> is instantiated 
    Xyzzy<BarOnly> baronly; // Xyzzy<BarOnly> is instantiated 

    foobar.CallFoo();   // Calls FooBar::foo() 
    foobar.CallBar();   // Calls FooBar::bar() 

    baronly.CallBar();  // Calls BarOnly::bar() 

    return 0; 
} 

Ceci est valable, même si Xyzzy :: CallFoo() n'est pas instanciable parce qu'il n'y a pas une telle chose comme BarOnly :: foo(). Cette fonctionnalité est souvent utilisée comme outil de métaprogrammation de modèle. Notez toutefois que "l'instanciation" d'un modèle ne correspond pas directement à la quantité de code objet générée. Cela dépendra de l'implémentation de votre compilateur/éditeur de liens.

+0

Nous devrions également noter que toutes les fonctions ne peuvent même pas être instanciées et cela est acceptable tant qu'elles ne sont pas appelées. –

+0

Terminé. J'ai pensé à cela lors de la réponse initiale, mais était juste trop paresseux pour écrire une explication complète. –

+0

Est-il possible de marquer la méthode à instancier par force (c'est-à-dire d'empêcher son optimisation) sans la rendre virtuelle? Merci! – Serge

1

Habituellement, oui.

Tout le compilateur sait vraiment que votre programme peut créer au moins une instance de chaque classe. Mais il ne sait pas ce que vous ferez avec ces instances. Donc, le code sera presque certain d'être généré.

Cela dit, si les méthodes en question sont pas virtuelle, et ne sont jamais appelés, l'éditeur de liens peut les supprimer avec ses caractéristiques de suppression de code mort normales. Donc le code généré (et compilé) ne sera pas dans le fichier EXE final.

De plus, cela dépendra largement du compilateur C++ utilisé car ils ne sont pas tous identiques.

2

Je pense que cela dépend du compilateur et des paramètres. Par exemple, je crois que MSVC6 a tout généré, mais pas VS2005. La spécification indique que le compilateur ne devrait pas, mais dans le monde réel, cela dépend du compilateur réel (il y a beaucoup de solutions de rechange en boost pour MSVC6, par exemple). L'éditeur de liens peut supprimer les fonctions non référencées si/opt: ref est activé (pour VS, des options équivalentes existent pour d'autres compilateurs).

+2

Bon vieux MSVC6 et modèles, ah les jours ... l'horreur. – QBziZ