2012-10-13 2 views
4

J'ai commencé à jouer avec les modèles extern un peu et je suis tombé sur un problème sur lequel je ne trouve aucune information pertinente. Dites que j'ai un modèle de classe avec une fonction ami non-modèle (définie dans la déclaration de modèle de classe). Je déclare quelques instanciations de template pour la classe, mais comment déclarer la fonction friend en tant qu'ext extern?Fonctions de classe de modèle externe et ami non-modèle

Voici quelques exemples de code:

// --- test.h --- 

template <typename T> 
class Foo { 
    private: 
    T value; 
    public: 
    friend void some_friend_function(Foo<T>& obj) { 
     obj.value -= T(42); 
    }; 

    void some_member_function(T rhs) { value += rhs; }; 

}; 

extern template class Foo<int>; 
//extern void some_friend_function(Foo<int>&); // I tried this also... 


// --- test.cpp --- 

#include "test.h" 

template class Foo<int>; 
//void some_friend_function(Foo<int>&);   // ... with this. 

Lorsque je compile ci-dessus (avec ou sans les lignes de commentaires), je ne reçois que le symbole exporté suivant:

0000000000000000 W _ZN3FooIiE20some_member_functionEi 

Ainsi, le non Les fonctions d'ami -template ne sont définitivement pas instanciées (et extern 'd) avec l'instanciation explicite du modèle de classe. Est-ce normal? Au moins, c'est ce que produit GCC (testé sur 4.6.3 et 4.7.2).

Y a-t-il un moyen pour que la fonction friend soit marquée extern? Je sais que ce n'est pas un énorme problème, car je peux vivre avec les fonctions d'amis instanciées comme nécessaire (ie, non extern), mais je suis curieux de savoir s'il y a un moyen de le faire, sinon , était-ce un oubli ou une chose délibérée?

EDIT: Les solutions de contournement évident

Ma question est spécifiquement sur les fonctions d'ami non-modèle, pas de trouver une solution pour éviter le problème, ce qui est trivial. La première solution évidente est la suivante:

template <typename T> 
class Foo { 
    private: 
    T value; 
    public: 
    template <typename U> 
    friend void some_friend_function(Foo<U>& obj) { 
     obj.value -= T(42); 
    }; 
}; 

extern template class Foo<int>; 
extern template void some_friend_function(Foo<int>&); 

// --- in cpp file: --- 

template class Foo<int>; 
template void some_friend_function(Foo<int>&); 

Et un autre, ce qui correspond plus étroitement, mais est plus gênant, est la suivante:

template <typename T> class Foo; // forward-declare. 

template <typename T> 
void some_friend_function(Foo<T>&); // declaration. 

template <typename T> 
class Foo { 
    private: 
    T value; 
    public: 
    friend void some_friend_function<>(Foo<T>& obj); // befriend the T-specialization. 
}; 

template <typename T> 
void some_friend_function(Foo<T>& obj) { // definition. 
    obj.value -= T(42); 
}; 

extern template class Foo<int>; 
extern template void some_friend_function(Foo<int>&); 

// --- in cpp file: --- 

template class Foo<int>; 
template void some_friend_function(Foo<int>&); 
+0

Je ne pense pas que ce que vous demandez est possible. Une fonction amie définie en ligne n'est détectable que via ADL. Vous ne pouvez pas obtenir un pointeur vers cette fonction et donc l'externaliser ne devrait pas être possible non plus. Une solution simple consiste à déclarer la signature des amis dans la déclaration de classe et à fournir la définition à l'extérieur. – Praetorian

+1

@ Prætorian "déclare la signature des amis dans la déclaration de classe et fournit la définition à l'extérieur." Ce n'est pas possible pour les fonctions amis non-modèles d'un modèle de classe, elles doivent être définies dans la déclaration de modèle de classe. "Une fonction ami définie en ligne n'est détectable que via ADL."Je sais, mais cela ne les rend-il pas plus comme des fonctions membres de la classe, et par conséquent, ne devraient-elles pas être instanciées avec toutes les fonctions membres lorsqu'une instanciation explicite apparaît? Cela semble être une faille bizarre, et l'ISO –

+0

@Mikael Persson: "[...] ne devraient-ils pas être instanciés [...]" 14.5.3/5: "Lorsqu'une fonction est définie dans une déclaration de fonction d'ami dans une classe template, la fonction est définie à chaque instanciation du template de classe. La fonction est définie même si elle n'est jamais utilisée. [...] ".Est-ce que vous recherchiez dans votre commentaire? – dyp

Répondre

0

L'effet d'une « classe template extern » est de déclarer explicitement instanciation à être disponible. L'effet des déclarations d'instanciation explicite ne sont pas applicables à inline fonctions ou spécialisations de modèle (14.7.2 [temp.explicit] paragraphe 10):

À l'exception des fonctions en ligne et spécialisations de modèle de classe, les déclarations d'instanciation explicites ont pour effet de supprimer l'instanciation implicite de l'entité à laquelle ils se réfèrent.

Depuis une définition de fonction friend dans une définition de classe est nécessairement une fonction inline, il reste une fonction indépendante inline de la déclaration d'instanciation explicite du modèle (et, comme vous l'avez noté correctement, il est pas un modèle et ne suit pas les règles d'instanciation de modèles de toute façon).

Questions connexes