IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

friend & espaces de nommage


Sujet :

Langage C++

  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut friend & espaces de nommage
    Hello,

    J'ai défini un opérateur binaire * comme suit (il ne fait pas grand chose pour l'instant, j'en suis conscient) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    template <class T1, template<class> class StorageT1,
              class T2, template<class> class StorageT2>
    Matrix<T1, StorageT1>
    operator*(const Matrix<T1, StorageT1>& matrix1, const Matrix<T2, StorageT2>& matrix2)
    {
    	Matrix<T1, StorageT1> outMatrix(matrix1.nbRows, matrix2.nbColumns);
     
    	return outMatrix;
    }
    Lorsque je crée 3 matrices (qui sont accessoirement exactement du même type), et que je fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    matrice3 = matrice1* matrice2;
    J'obtiens l'erreur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ambiguous overload foroperator*’

  2. #2
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Exemple compilable si possible. Je ne vois pas de probleme a priori et n'en ai pas avec:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    template <typename T> struct Storage;
     
    template <typename T, template <typename> class S>
    struct Matrix {};
     
    template <class T1, template<class> class StorageT1,
              class T2, template<class> class StorageT2>
    Matrix<T1, StorageT1>
    operator*(const Matrix<T1, StorageT1>& matrix1, const Matrix<T2, StorageT2>& matrix2)
    {
        Matrix<T1, StorageT1> outMatrix;
     
        return outMatrix;
    }
     
    int main()
    {
        Matrix<int, Storage> m1, m2, m3;
        m3 = m1*m2;
        return 0;
    }

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Alors en fait, ça semble venir du fait que la classe Matrix est en fait définie dans un espace de nommage, que l'opérateur soit défini en dehors de tout espace de nommage, et que l'opérateur * soit défini comme friend dans la classe Matrix.

    Je précise que dans le bout de code que j'avais donné, j'avais, pour des raisons de lisibilité, enlevé les références à l'espace de nommage précédent le nom de la classe Matrix.

    Quand j'enlève la déclaration friend, ça compile, mais ça m'ennuie, car je n'ai plus accès aux données internes de la matrice.

    Apparemment, le compilateur ne fait pas le lien entre la déclaration hors de l'espace de nommage (celle que je vous ai présentée), et la déclaration friend. Il les voit comme deux surcharges différentes, et en déduit une ambiguïté. J'ai essayé, dans la déclaration friend, de rajouter l'opérateur de portée ::

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template <class T1, template<class> class StorageT1,
              class T2, template<class> class StorageT2>
    friend Matrix<T1, StorageT1>
    ::operator*(const Matrix<T1, StorageT1>& matrix1, const Matrix<T2, StorageT2>& matrix2);
    mais j'obtiens l'erreur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ISO C++ forbids declaration of ‘operator*’ with no type
    EDIT : en fait, mon problème ressemble assez à celui-ci. J'essaye de mettre en œuvre la solution proposée, mais ce n'est pas évident...

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Par ailleurs, j'avais initialement mis mon opérateur à l'intérieur de l'espace de nommage concerné, et ça amrchait très bien.

    Mais il m'a été dit qu"il fallait mettre les opérateurs binaires hors de tout espace de nommage, d'où mes actuels problèmes. Qu'en pensez-vous ?

  5. #5
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Pour moi il faut mettre les operateurs libres dans le meme espace de nommage que les classes qu'ils manipulent. (Ce qu'il ne faut pas faire, c'est mettre des operateurs binaires comme membres de la classe, c'est peut-etre avec ca que tu confondais).

  6. #6
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Citation Envoyé par oodini Voir le message
    en fait, mon problème ressemble assez à celui-ci. J'essaye de mettre en œuvre la solution proposée, mais ce n'est pas évident...
    Bon, après avoir lutté pour faire la déclaration anticipée de mes templates compliqués, au final, il considère toujours qu'il y a un opérateur * défini dans l'espace de nommage à cause de la déclaration friend, malgré ce que j'ai ajouté (en rouge) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template <class T1, template<class> class StorageT1,
                   class T2, template<class> class StorageT2>
    friend Matrix<T1, StorageT1>
    (::operator*) (const Matrix<T1, StorageT1>& matrix1, const Matrix<T2, StorageT2>& matrix2);

  7. #7
    screetch
    Invité(e)
    Par défaut
    ou bien une predeclaration de ton operateur * dans le namespace correct.
    en effet, si lorsque tu mets ta declaration friend, le compilateur n'a pas encore vu ton operateur *, il va declarer l'operateur * dans le namespace courant.

    si en revanche un operateur * a été declaré avant, et dans un namespace accessible, il va utiliser cette declaration.

    le problème est donc que en ajoutant friend, tu as declaré un operator* au mauvais endroit.

    remarque subsidiaire, ton operateur * dans le namespace global n'est pas friend de la classe puisque le compilo a compris ca différemment.

  8. #8
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    En l'occurrence, à présent, je déclare au début de mon code (mais après la déclaration anticipée de Matrix, rendue nécessaire...), en dehors de tout espace de nom :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    template <class T1, template<class> class StorageT1,
              class T2, template<class> class StorageT2>
    monNamespace::Matrix<T1, StorageT1>
    operator * (const monNamespace::Matrix<T1, StorageT1>& matrix1, const monNamespace::Matrix<T2, StorageT2>& matrix2);
    Ça devrait donc être bon.

  9. #9
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    En général on met les opérateurs dans le même espace de nommage pour profiter de l'ADL.

    Si tu les mets complétement au dehors j'ai peur que si un utilisateur définie le même opérateur que toi de manière générique (operator*(const T&, const T&)) dans son propre namespace et utilise ensuite dans son namespace tes matrices avec cet opérateur, l'appel ne soit pas celui attendu (alors qu'avec l'ADL ca serait bon).

    Je t'invite au passage à lire les articles de Herb Sutter sur GotW à propos du concept de classe ("What is in a class ?" pour le titre de mémoire).

  10. #10
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Pour illustrer mon propos précédent :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
     
    #include<iostream>
     
    namespace N
    {
    	template<class T>
    	struct A;
    }
     
    template<class T>
    N::A<T> operator+(const N::A<T>&, const N::A<T>&);
     
    namespace N
    {
    	template<class T>
    	struct A
    	{
    		friend A (::operator+<>)(const A&, const A&);
    	};
    }
     
    template<class T>
    N::A<T> operator+(const N::A<T>&, const N::A<T>&)
    { 
    	std::cout << 0;
    	return N::A<T>();
    }
     
    namespace M
    {
    	template<class T>
    	T operator+(const T&, const T&)
    	{
    		std::cout << 1;
    		return T();
    	}
     
    	void foo()
    	{
    		N::A<int> a, b;
    		a+b;
    	}
    }
     
    int main()
    {
    	N::A<int> a, b;
    	a+b;
    	M::foo();
    }
    Ce code représente ce que tu fais actuellement avec un utilisateur qui rajoute le namespace M, l'opération a+b de foo affiche 1 : ce n'est pas le comportement que tu as prévu.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     
    #include<iostream>
     
    namespace N
    {
    	template<class T>
    	struct A;
     
    	template<class T>
    	A<T> operator+(const A<T>&, const A<T>&);
     
    	template<class T>
    	struct A
    	{
    		friend A operator+<>(const A&, const A&);
    	};
     
    	template<class T>
    	A<T> operator+(const A<T>&, const A<T>&)
    	{ 
    		std::cout << 0;
    		return A<T>();
    	}
     
    }
     
    namespace M
    {
    	template<class T>
    	T operator+(const T&, const T&)
    	{
    		std::cout << 1;
    		return T();
    	}
     
    	void foo()
    	{
    		N::A<int> a, b;
    		a+b;
    	}
    }
     
    int main()
    {
    	N::A<int> a, b;
    	a+b;
    	M::foo();
    }
    La même chose en restant dans le namespace de la classe, cette fois l'opération a+b de foo a bien le comportement attendu : cela affiche 0.

    En conclusion : les opérateurs doivent être dans le namespace des opérandes.

  11. #11
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    En général on met les opérateurs dans le même espace de nommage pour profiter de l'ADL.

    Si tu les mets complétement au dehors j'ai peur que si un utilisateur définie le même opérateur que toi de manière générique (operator*(const T&, const T&)) dans son propre namespace et utilise ensuite dans son namespace tes matrices avec cet opérateur, l'appel ne soit pas celui attendu (alors qu'avec l'ADL ca serait bon).
    Malheureusement, on m'impose de le définir en dehors de l'espace de nommage...

    Citation Envoyé par Flob90 Voir le message
    Je t'invite au passage à lire les articles de Herb Sutter sur GotW à propos du concept de classe ("What is in a class ?" pour le titre de mémoire).
    Sur cette page, je n'ai rien trouvé qui s'en rapproche.

  12. #12
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    C'est un projet scolaire ou un projet "réel" ? Dans le second cas tu pourrais essayer d'en discuter avec ton responsable.

    http://www.gotw.ca/publications/mill02.htm

    NB: J'ai posté un message supplémentaire pendant que tu écrivais le tien. Ca te montre que le défaut introduit est assez fort.

  13. #13
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    C'est un projet réél.

    Je te remercie beaucoup pour le bout de code que tu as fait l'effort d'écrire.

    Je suis en train de bosser dessus.

    EDIT : c'est édifiant, effectivement

  14. #14
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Bon, je suis allé voir mon responsable muni de ton code, avec al suggestion de jeter un œil sur Wikipedia (ADL).

    Comme j'avais déjà essayé ce matin de le convaincre de rester dans le namespace, ça a été un peu tendu au début, mais finalement, j'ai remporté la victoire.

    Merci beaucoup !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Flash8] Espace de nommage dans un webservice
    Par memess dans le forum Flash
    Réponses: 1
    Dernier message: 01/03/2007, 09h19
  2. [c++] Mettre un callback dans un espace de nommage ou une class
    Par Spartan03 dans le forum GTK+ avec C & C++
    Réponses: 1
    Dernier message: 20/01/2007, 16h12
  3. Réponses: 2
    Dernier message: 05/09/2006, 10h08
  4. L'espace de nommage
    Par Shakan972 dans le forum C++
    Réponses: 1
    Dernier message: 02/11/2005, 15h49
  5. Réponses: 3
    Dernier message: 10/01/2005, 12h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo