Modèle amie fonction d'une classe template
J'ai été aux prises avec le problème décrit dans cette question (la déclaration d'une fonction de modèle comme un ami d'un modèle de classe), et je crois que la 2ème réponse est ce que je veux faire (avant de déclarer la fonction de modèle, puis le nom d'une spécialisation comme un ami). J'ai une question un peu différente de la solution est correcte ou arrive juste à travailler dans Visual C++ 2008.
Code de Test est:
#include <iostream>
//forward declarations
template <typename T>
class test;
template <typename T>
std::ostream& operator<<(std::ostream &out, const test<T> &t);
template <typename T>
class test {
friend std::ostream& operator<< <T>(std::ostream &out, const test<T> &t);
//alternative friend declaration
//template <typename U>
//friend std::ostream& operator<<(std::ostream &out, const test<T> &t);
//rest of class
};
template <typename T>
std::ostream& operator<<(std::ostream &out, const test<T> &t) {
//output function defined here
}
Tout d'abord, une chose étrange que j'ai trouvé était que si je change la déclaration anticipée de operator<<
de sorte qu'il ne correspond pas (par exemple, std::ostream& operator<<(std::ostream &out, int fake);
, tout compile et fonctionne correctement (pour être clair, je n'ai pas besoin de définir une telle fonction, seul le déclarer). Cependant, comme liés à la question, le retrait de la déclaration anticipée sont les causes d'un problème, car le compilateur semble penser que je suis déclaration d'un membre de données à la place d'un ami de la fonction. Je suis assez sûr que ce comportement est un Visual C++ 2008 bug.
La chose intéressante est que lorsque je retire la déclaration et l'utilisation de la variante de l'ami de la déclaration dans le code ci-dessus. Notez que le paramètre de modèle U
n'apparaît pas dans la suite de la signature. De plus, cette méthode compile et fonctionne correctement (sans rien changer d'autre). Ma question est de savoir si cela est conforme à la norme ou à une idiosyncrasie de Visual C++ 2008 (je ne pouvais pas trouver une bonne réponse dans mes livres de référence).
Noter que, si un ami de la déclaration de template <typename U> friend ... const test<U> &t);
fonctionne aussi, cela donne effectivement chaque instance de l'opérateur friend
accès à toute instance de test
, tout ce que je veux, c'est que les membres privés de test<T>
ne devrait être accessible à partir de operator<< <T>
. J'ai testé ce par l'instanciation d'un test<int>
à l'intérieur de la operator<<
et l'accès à un membre privé, ce qui devrait provoquer une erreur de compilation lorsque j'essaie de sortie d'un test<double>
.
Synopsis: le Retrait de la déclaration et de passer à l'alternative ami de déclaration dans le code ci-dessus semble produire le même résultat (en Visual C++ 2008) -- est-ce code fait-il correct?
Mise à JOUR: Toutes les modifications ci-dessus pour le code ne fonctionne pas sous gcc, donc je suppose que ce sont des erreurs ou des "features" dans le compilateur Visual C++. Encore, je vous en serais reconnaissant idées de personnes familières avec le standard.
using namespace std;
avant la déclaration de la classe supprime la nécessité pour la déclaration, qui je suppose est un des effets secondaires de la (possible) de compilateur bug.Comme pour mon comment - pouvez-vous ajouter explicitement les exemples (y compris l'instanciation) qui vous disent de travail? Verbalement, il est assez difficile de comprendre ce que tu veux dire pour chaque exemple.
OriginalL'auteur Sumudu Fernando | 2009-11-24
Vous devez vous connecter pour publier un commentaire.
...si je change la déclaration anticipée de l'opérateur<< de sorte qu'il ne correspond pas à
Un ami de la fonction doit être considérée comme un type spécial de déclaration. En essence, le compilateur ne suffisant pour analyser la déclaration toutefois pas de sémantique de la vérification aura lieu, sauf si vous avez réellement se spécialiser la classe.
Après avoir fait votre modification proposée, si vous puis instancier
test
, vous obtiendrez une erreur sur les déclarations ne correspondent pas:...Cependant ... retrait de la déclaration anticipée sont les causes d'un problème
Le compilateur essaie d'analyser la déclaration de stocker jusqu'à ce que le modèle de classe est spécialisée. Au cours de l'analyse, le compilateur arrive le
<
dans la déclaration:La seule façon que
operator<<
pourrait être suivie par<
est de savoir si c'est un modèle, si une recherche est effectuée pour vérifier que c'est un modèle. Si un modèle de fonction est trouvée, alors le<
est considéré comme le début d'arguments de modèle.Lorsque vous retirez la déclaration anticipée, aucun modèle n'est trouvé et
operator<<
est considéré comme un objet. (C'est aussi pourquoi, lorsque vous ajoutezusing namespace std
le code continue de compiler car il doit y avoir des déclarations de modèles pouroperator<<
)....quand j'enlève la déclaration et l'utilisation de la variante de l'ami de la déclaration dans le code ci-dessus. Notez que le paramètre de modèle U n'apparaît pas dans la suite de la signature...
Il n'est pas nécessaire que tous les paramètres du modèle de être utilisés dans les arguments d'une fonction de modèle. L'alternative déclaration est pour un nouveau modèle de fonction qui ne sera exigible en cas de déclaration dans l'espace de noms et la spécification explicite arguments de modèle.
Un exemple simple:
...est-ce code fait-il correct?..
Bien il y a deux parties. La première est que l'alternative ami de la fonction ne fait pas référence à la déclaration plus tard dans le champ d'application:
L'ami de la fonction serait en fait être déclarés dans l'espace de noms pour chaque spécialisation:
Chaque spécialisation de
operator<< <U>
auront accès à la spécialisation selon le type de ses paramètrestest<T>
. Donc, en substance, l'accès est restreint comme vous le désirez. Cependant, comme je l'ai mentionné avant, ces fonctions sont essentiellement inutilisable en tant qu'opérateurs, puisque vous devez utiliser la fonction syntaxe d'appel:Que par les réponses à la question précédente, vous pouvez utiliser la déclaration anticipée comme suggéré par litb, ou vous allez à la définition de l'ami de la fonction en ligne, comme par Dr_Asik de l' réponse (qui sera probablement ce que je ferais).
Mise à JOUR: 2ème Commentaire
...la modification de la déclaration anticipée avant la classe; l'un dans la classe correspond à la fonction que je mettre en œuvre plus tard...
Comme je l'ai souligné ci-dessus, le compilateur vérifie si
operator<<
est un modèle lorsqu'il voit le<
dans la déclaration:Ce faire, il recherche le nom et vérifier si il est un modèle. Tant que vous avez un mannequin avant la déclaration de ces "trucs", le compilateur dans le traitement de votre ami comme un nom de modèle et donc la
<
est considéré comme le début d'un modèle de liste d'arguments.Plus tard, lors de l'instanciation de la classe, vous en avez un modèle valide pour le match. En essence, vous êtes juste de tromper le compilateur dans le traitement de l'ami comme un modèle de spécialisation.
Vous pouvez le faire ici parce que (comme je l'ai dit plus tôt), pas de sémantique de la vérification a lieu en ce moment.
<<
opérateur de la manière habituelle. J'ai aussi vérifié que la fonction opérateur a accès corrects (par exemple, il ne pouvait pas accès aux membres privés d'unetest<int>
si il a été appelé pour imprimer untest<double>
. C'est le cas avec le code écrit, avec une "fausse" déclaration anticipée, et avec l'autre ami de la déclaration.Aussi, j'ai réalisé que vous avez probablement mal compris ce que j'ai dit sur la "fausse" déclaration-je parle uniquement sur la modification de la déclaration anticipée avant la classe; l'un dans la classe correspond à la fonction que je mettre en œuvre plus tard (donc à l'instanciation, le besoin de modèle de fonction a déjà été analysé).
J'ai ajouté une mise à jour pour répondre à votre deuxième commentaire. Comme pour la première, pouvez-vous s'il vous plaît modifier votre question à inclure l'exemple qui vous disent "compile et fonctionne correctement", mais utilise l'alternative ami modèle de fonction? Quand je fais ça ici, j'ai des erreurs de l'accès par les membres dans l'espace de noms de modèle.
OriginalL'auteur Richard Corden