2010-06-15 6 views
3

J'ai écrit le code suivant:Comment définir et utiliser une fonction friend dans une classe temlate avec le même template?

#include <iostream> 
using namespace std; 

template <class T> 
class AA 
{ 
    T a; 

public: 
AA() 
{ 
a = 7; 
} 

friend void print(const AA<T> & z); 
}; 

template <class T> 
void print(const AA<T> & z) 
{ 
    cout<<"Print: "<<z.a<<endl; 
} 

void main() 
{ 
AA<int> a; 
print<int>(a); 
} 

Et obtenir l'erreur suivante:

error C2248: 'AA<T>::a' : cannot access private member declared in class 'AA<T>' 
1>  with 
1>  [ 
1>   T=int 
1>  ] 
1>  c:\users\narek\documents\visual studio 2008\projects\aaa\aaa\a.cpp(7) : see declaration of 'AA<T>::a' 
1>  with 
1>  [ 
1>   T=int 
1>  ] 
1>  c:\users\narek\documents\visual studio 2008\projects\aaa\aaa\a.cpp(30) : see reference to function template instantiation 'void print<int>(const AA<T> &)' being compiled 
1>  with 
1>  [ 
1>   T=int 
1>  ] 

Qu'est-ce qui ne va pas?

P.S. J'utilise Visual Studio 2008.

Répondre

3

Le problème est que lorsque vous faites quelque chose comme

template<class T> 
class AA {friend void print(const AA<T>&);}; 

et vous instancier AA avec comme celui-ci

AA<int> a; 

la déclaration d'ami sera instancié comme

friend void print(const AA<int>&); 

qui est une fonction sans modèle! Cela signifie que le compilateur ne correspondra pas à la déclaration d'ami avec votre fonction print.

La solution consiste essentiellement à déclarer print avant AA et de dire explicitement au compilateur que votre déclaration d'ami parle d'une fonction de modèle. Comme ceci:

#include <iostream> 
using namespace std; 

//forward declare AA because print needs it 
template<class T> 
class AA; 

//declare print before AA to make the friend declaration 
//match with this function 
template<class T> 
void print(const AA<T> & z); 

template <class T> 
class AA 
{ 
     //the <> is needed to make sure the compiler knows we're 
     //dealing with a template function here 
     friend void print<>(const AA<T> & z); 

    public: 
     AA() {a = 7;} 

    private: 
     T a; 
}; 

//implement print 
template<class T> 
void print(const AA<T> & z) 
{ 
    cout<<"Print: "<<z.a<<endl; 
} 

int main() 
{ 
    AA<int> a; 
    print(a); 
} 

Il est intéressant de voir ce qui se passe si vous n'ajoutez pas la <> dans la déclaration d'ami. Vous obtiendrez une erreur de l'éditeur de liens. Pourquoi? Eh bien, parce que le compilateur ne peut pas correspondre à la déclaration d'ami avec votre fonction modèle print, il assumera implicitement une fonction prototype avec

void print(const AA<int>&); 

existe. Comme je n'ai pas explicitement fourni un paramètre de template à l'appel à print (ce qui n'est pas nécessaire parce que le compilateur devrait être capable de le déduire), le compilateur fera correspondre cet appel avec la fonction déclarée comme ami. Cette fonction n'est implémentée nulle part, d'où l'erreur de l'éditeur de liens.

+0

Il fonctionne. Si étrange...! Si la fonction est une fonction amie, cela signifie que ce n'est pas une fonction de classe. Comment le compilateur peut-il «penser» que la fonction est la fonction d'une classe? Ou vous dites quelque chose de différent en disant "en classe"? – Narek

+0

Il s'est avéré que mon explication n'était pas tout à fait correcte. Edited it et il devrait être plus clair maintenant :) – Job

+0

Pourquoi devrais-je déclarer imprimer avant AA? J'ai précédemment créé des fonctions frind dans ma classe et implémenté ces fonctions dans un fichier .cc (après la classe) et cela fonctionne. Pourquoi maintenant la fonction frite devrait être avant AA? Je veux dire comment cela aide le compilateur? – Narek

1

Vous pouvez également définir la fonction ami dans la définition de la classe:

#include <iostream> 
using namespace std; 

template <class T> 
class AA 
{ 
    T a; 
    public: 
    AA() 
    { 
     a = 7; 
    } 

    friend void print(const AA<T> &z) 
    { 
     cout<<"Print: "<<z.a<<endl; 
    } 
}; 

int main() 
{ 
    AA<int> a; 
    print(a); 
}