
Soit la méthode "print" d'une classe située dans le namespace oln. Soit p un point2d. Je souhaite afficher mon point2d, et j'écris : os << p << std::endl; Malheureusement, le compilateur ne voit pas operator<<(ostream&, const point2d&) pourtant défini en dehors de tout namespace dans point2d.hh. Pour afficher mon point, je dois alors écrire : ::operator<<(os, p); C'est pas très joli. C'est moi qui fume, ou bien ? -- astrid

astrid <wang_a@epita.fr> writes:
Soit la méthode "print" d'une classe située dans le namespace oln. Soit p un point2d.
Je souhaite afficher mon point2d, et j'écris : os << p << std::endl;
Malheureusement, le compilateur ne voit pas operator<<(ostream&, const point2d&) pourtant défini en dehors de tout namespace dans point2d.hh.
Pour afficher mon point, je dois alors écrire : ::operator<<(os, p);
C'est pas très joli. C'est moi qui fume, ou bien ?
Je n'arrive pas à reproduire le pb. Tu peux donner un bout de code à compiler avec olena qui rate ?

Nicolas Burrus <burrus_n@lrde.epita.fr> writes:
astrid <wang_a@epita.fr> writes:
Soit la méthode "print" d'une classe située dans le namespace oln. Soit p un point2d.
Je souhaite afficher mon point2d, et j'écris : os << p << std::endl;
Malheureusement, le compilateur ne voit pas operator<<(ostream&, const point2d&) pourtant défini en dehors de tout namespace dans point2d.hh.
Pour afficher mon point, je dois alors écrire : ::operator<<(os, p);
C'est pas très joli. C'est moi qui fume, ou bien ?
Je n'arrive pas à reproduire le pb. Tu peux donner un bout de code à compiler avec olena qui rate ?
Euh... Pour l'instant cette ligne est perdue au milieu d'un monstro-code. Je vais essayer de te préparer une version élaguée :) Merci de t'être penché sur la question. -- astrid

astrid <wang_a@epita.fr> writes: [...]
Pour afficher mon point, je dois alors écrire : ::operator<<(os, p);
C'est pas très joli. C'est moi qui fume, ou bien ?
Je vote pour un opérateur déclaré dans le mauvais namespace. En effet, le code suivant : namespace foo { struct bar; } namespace std { class ostream& std::ostream& operator<<(std::ostream&, char); } std::ostream& operator<<(std::ostream&, const foo::bar&); ... est une faute de style, l'implémentation de "op<<" pour "bar" devrait être définie dans le namespace foo. Voir le koening lookup: une fonction hors de foo: et hors de std: qui invoque "cout << bar()" n'a pas de raison d'aller chercher l'opérateur dans le namespace parent si des _candidats_, même incompatibles, sont trouvés dans le namespace de l'un ou l'autre des arguments, et il y a des candidats dans le namespace des ostreams (std). Mais c'est une situation assez obscure et les compilateurs sont tous plus ou moins tolérants dans leur recherche d'une implémentation compatible. Je voudrais bien voir ton code aussi. -- . Raphaël Poss . . _ - --------\ : EPITA CSI 2003 ICQ 1757157 | | EpX -- ACU -- Activ' GnuPG fp bda2eb602866390c7a7d : \------ - _ . . a13ad7c86dd33b72e72b '

astrid <wang_a@epita.fr> writes: Bon, j'ai un bout de code : ------------------------------------------------------- #include <iostream> #include <oln/basics2d.hh> namespace oln { namespace foo { template <class I> struct A { A(const typename I::point_type& p) : p(p) {} typename I::point_type p; }; template <class I> std::ostream& operator<<(std::ostream& os, const A<I>& a) { os << a.p << std::endl; // KO // operator<<(os, a.p) << std::endl; // KO // ::operator<<(os, a.p) << std::endl; // OK return os; } } // foo } // oln using namespace oln; using namespace foo; using namespace ntg; int main() { const A<image2d<int_u8> >& a(point2d(7,13)); std::cout << a << std::endl; } ------------------------------------------------------- Je compile avec g++-3.2 g++-3.2 -I ../olena -I ../integre -I ../metalic pouet.cc -o pouet pouet.cc: In function `std::ostream& oln::foo::operator<<(std::ostream&, const oln::foo::A<I>&) [with I = oln::image2d<ntg::int_u8, mlc::final>]': pouet.cc:42: instantiated from here pouet.cc:23: no match for `std::basic_ostream<char, std::char_traits<char> >& << const oln::point2d&' operator /usr/include/c++/3.2/bits/ostream.tcc:55: candidates are: [... plein de gens qui n'ont rien a voir ...] etc. :( -- astrid

astrid <wang_a@epita.fr> writes:
astrid <wang_a@epita.fr> writes:
Bon, j'ai un bout de code :
------------------------------------------------------- #include <iostream> #include <oln/basics2d.hh>
namespace oln { namespace foo {
template <class I> struct A { A(const typename I::point_type& p) : p(p) {}
typename I::point_type p; };
template <class I> std::ostream& operator<<(std::ostream& os, const A<I>& a) { os << a.p << std::endl; // KO // operator<<(os, a.p) << std::endl; // KO // ::operator<<(os, a.p) << std::endl; // OK return os; }
} // foo } // oln
using namespace oln; using namespace foo; using namespace ntg;
int main() { const A<image2d<int_u8> >& a(point2d(7,13));
std::cout << a << std::endl; } -------------------------------------------------------
Je compile avec g++-3.2 g++-3.2 -I ../olena -I ../integre -I ../metalic pouet.cc -o pouet
pouet.cc: In function `std::ostream& oln::foo::operator<<(std::ostream&, const oln::foo::A<I>&) [with I = oln::image2d<ntg::int_u8, mlc::final>]': pouet.cc:42: instantiated from here pouet.cc:23: no match for `std::basic_ostream<char, std::char_traits<char> >& << const oln::point2d&' operator /usr/include/c++/3.2/bits/ostream.tcc:55: candidates are: [... plein de gens qui n'ont rien a voir ...] etc.
:(
Je viens de dépiler cette histoire :) Bon, après investigation, c'est tout à fait normal. Comme d'hab avec le C++, c'est assez tordu. Récapitulation des règles de lookup en c++ pour une configuration du style : namespace n1 { void bar(char*); namespace n2 { void bar(int); void foo() { bar("mystring"); } //... } } On cherche "bar". L'ensemble des règles pour constituer l'ensemble des "bar" possibles sont : - Dépiler les namespaces supérieurs jusqu'à ce qu'on trouve 1 symbole nommé "bar". Si on en trouve 1, chercher toutes les occurences de "bar" dans ce scope, et s'arrêter (on ne va pas dans les namespaces encore plus hauts). Ici, on va trouver un "bar" dans n2 donc on s'arrete à n2. Seul bar(int) sera donc proposé par cette règle. - Regarder dans les namespaces des arguments de la fonction, ici dans le namespace de "mystring", donc rien. Ensuite l'ensemble des "bar" trouvé est soumis aux règles de l'overloading. Dans cet exemple, bar(char*) ne sera pas analysé. Il se passe la même chose avec nos points : - Dans oln::foo::operator<< , l'appel à operator<< cherche d'abord dans oln::foo, et trouve un operator<< (lui meme en l'occurence). Du coup il s'arrete et ne cherche pas plus loin. - Il regarde aussi dans le namespace de l'argument (a.p), et va donc voir dans oln::. Il n'y trouve rien. En aucun cas il n'a eu à aller voir dans le scope global ::. Solutions : - Mettre les operator<< dans le meme namespace que le type concerné (ici oln:: pour point2d) - Mettre _tous_ les operator<< dans le namespace global ::

Nicolas Burrus <burrus_n@lrde.epita.fr> writes:
astrid <wang_a@epita.fr> writes:
[...]
Solutions :
- Mettre les operator<< dans le meme namespace que le type concerné (ici oln:: pour point2d)
- Mettre _tous_ les operator<< dans le namespace global ::
Ok, merci pour cette analyse, Nes. :) C'est effectivement la deuxième solution qui est actuellement adoptée dans Olena. Mais la première solution ne serait-elle pas plus 'user-friendly' ? -- astrid

astrid <wang_a@epita.fr> writes: [...]
Ok, merci pour cette analyse, Nes. :)
C'est effectivement la deuxième solution qui est actuellement adoptée dans Olena. Mais la première solution ne serait-elle pas plus 'user-friendly' ?
Clairement, je trouve. -- . Raphaël Poss . . _ - --------\ : EPITA CSI 2003 ICQ 1757157 | | EpX -- ACU -- Activ' GnuPG fp bda2eb602866390c7a7d : \------ - _ . . a13ad7c86dd33b72e72b '

Raphaël Poss <raph@lrde.epita.fr> writes:
astrid <wang_a@epita.fr> writes:
[...]
Ok, merci pour cette analyse, Nes. :)
C'est effectivement la deuxième solution qui est actuellement adoptée dans Olena. Mais la première solution ne serait-elle pas plus 'user-friendly' ?
Clairement, je trouve.
Je trouve aussi, mais il me semble que theo avait un argument qe j'oublie tout le temps, qqn s'en souvient ? Je ne sais plus si il est encore pertinent ou pas.
participants (3)
-
astrid
-
Nicolas Burrus
-
Raphaël Poss