Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Ordre résolution des namespaces

11 réponses
Avatar
Korchkidu
Bonjour =E0 tous,

J'ai un truc comme suit :

#include <iostream>

namespace N1
{
namespace N2
{
class A
{
public:
void test()
{
std::cout<<"N1::N2::TestA"<<std::endl;
}
};
}

}

namespace N2
{
class A
{
public:
void test()
{
std::cout<<"subname::TestA"<<std::endl;
}
};

}

namespace N1
{
namespace N3
{
void monTest()
{
N2::A monA; // Probl=E8me ici. Je ne peux pas modifier cette
ligne...

monA.test();
}
}

}

int main()
{
name::subname2::monTest();

char key;
std::cin>>key;
return 0;

}

A la ligne "N2::A monA", j'aimerais lui dire de prendre le ::N2::A et
non pas le N1::N2::A.

Existe t'il un moyen de le faire proprement et de mani=E8re globale ? Je
pr=E9cise que si je dois modifier toutes les lignes qui posent probl=E8me,
=E7a risque de prendre plusieurs jours (et de rajouter des probl=E8mes).
C'est pour cette raison que je pr=E9f=E8re =E9viter ceci.

Merci d'avance pour votre aide.
K.

10 réponses

1 2
Avatar
pjb
Korchkidu writes:
[...]
A la ligne "N2::A monA", j'aimerais lui dire de prendre le ::N2::A et
non pas le N1::N2::A.



#define N2 ::N2
#include <source with N2::A monA.h>

Existe t'il un moyen de le faire proprement et de manière globale ? Je
précise que si je dois modifier toutes les lignes qui posent problème,
ça risque de prendre plusieurs jours (et de rajouter des problèmes).
C'est pour cette raison que je préfère éviter ceci.



De toutes façon c'est pas ça qui évitera les problèmes...


--
__Pascal Bourguignon__ http://www.informatimago.com/

"Our users will know fear and cower before our software! Ship it!
Ship it and let them flee like the dogs they are!"
Avatar
Korchkidu
On 2 août, 15:50, (Pascal J. Bourguignon)
wrote:
Korchkidu writes:
> [...]
> A la ligne "N2::A monA", j'aimerais lui dire de prendre le ::N2::A et
> non pas le N1::N2::A.

#define N2 ::N2
#include <source with N2::A monA.h>



Bonjour,

merci pour votre réponse. Malheureusement, je ne suis pas sûr que cela
marchera. Car parfois, j'utilise N1::N2...
Et puis cette solution ne me semble pas très propre... Je préfère
alors réécrire les lignes qui posent problème...

Merci de votre aide.
K.
Avatar
Patrick 'Zener' Brunet
Bonjour.

"Korchkidu" a écrit dans le message de news:

Bonjour à tous,

J'ai un truc comme suit :

#include <iostream>

namespace N1
{
namespace N2
{
class A
{
[...]



A la ligne "N2::A monA", j'aimerais lui dire de prendre le
::N2::A et non pas le N1::N2::A.



Qui est-ce qui disait récemment que le préfixage discriminant des
identifiants publics d'un même module est une pratique à bannir sans
hésitation ?

Au profit de noms plus simples tels que: open, write, save, etc. ?

Ben voilà... Sans parler de la lisibilité "humaine".

--
Cordialement.
--
* Patrick BRUNET www.ipzb.fr
* E-mail: lien sur http://zener131.eu/ContactMe
Avatar
Korchkidu
On Aug 3, 8:13 am, "Patrick 'Zener' Brunet"
wrote:

Qui est-ce qui disait récemment que le préfixage discriminant des
identifiants publics d'un même module est une pratique à bannir sans
hésitation ?

Au profit de noms plus simples tels que: open, write, save, etc. ?

Ben voilà... Sans parler de la lisibilité "humaine".


Bonjour,

Je ne suis pas sûr d'avoir compris votre réponse. pourriez-vous
détailler svp car je suis sûr que ça pourrait m'aider dans ma
quête...^^

Bonne journée.
K.
Avatar
Patrick 'Zener' Brunet
Bonsoir.

"Korchkidu" a écrit dans le message de news:

On Aug 3, 8:13 am, "Patrick 'Zener' Brunet"
wrote:

> Qui est-ce qui disait récemment que le préfixage discriminant
> des identifiants publics d'un même module est une pratique à
> bannir sans hésitation ?
>
> Au profit de noms plus simples tels que: open, write, save,
> etc. ?
>
> Ben voilà... Sans parler de la lisibilité "humaine".

Je ne suis pas sûr d'avoir compris votre réponse. pourriez-vous
détailler svp car je suis sûr que ça pourrait m'aider dans ma
quête...^^



Et bien, d'abord pour le contexte:
Je pense que la distinction entre fournisseurs de librairies et développeurs
finaux est purement arbitraire, et idéalement ne devrait pas exister: même
dans mes propres projets, je m'efforce de me doter de composants modulaires
et réutilisables, et donc je suis à tour de rôle fournisseur et utilisateur.

Dans cette optique, on a donc une librairie qui s'appuie sur d'autres et qui
en supportera d'autres, etc.

Ensuite, je ne sais pas vous, mais je fais des trucs qui sont
intrinsèquement complexes, alors je refuse de jouer au compilateur en
relisant mon code. Tout ce qui n'est pas évident (pour l'homme de l'art avec
au besoin quelques mots de commentaires) est forcément mal écrit.

Donc j'aime bien, en voyant un identifiant, savoir immédiatement de quoi il
fait partie, son type, ses limites, sa sémantique, etc. sans avoir à
remonter à la déclaration ni déchiffrer des paths de namespaces.

Ca me conduit à utiliser volontiers des identifiants très explicites, mais
aussi (je vais faire hurler là) la notation dite "hongroise" avec un jeu de
préfixes sophistiqués (pas ceux de µ$), mais ceci est un peu hors-sujet...

J'utilise aussi les namespaces pour le principe (et cela permet peut-être
des optimisations et des protections), mais de toute manière je préfixe les
classes, autres types et fonctions exportables d'une librairie donnée, pour
les yeux du lecteur, fût-ce moi-même a posteriori.

Sur la méthode, il y en a plusieurs, selon vos goûts: c'est vous qui devez
vous y retrouver au premier coup d'oeil, puis vos lecteurs quand ils auront
saisi votre logique par ailleurs systématique.

Par exemple, si vous aviez nommé vos divers projets Jupiter, Saturne et
Pluton, vous n'auriez aucun conflit entre:
- JupFile, JupString, JupComplex, JupDynArray...
- SatFile, SatString, SatComplex...
- PluComplex... vous m'avez compris.

C'est aussi compatible avec un préfixe de type comme ceux que j'emploie.
Par exemple, je préfixe mes classes par un C et celles-ci sont tirées d'un
de mes projets, dont le trigramme est 'mic':

CmicArray
CmicStack
...
CmicMapBTree
CmicMapBTreeCursor
CmicMapBTreeDataNode
CmicMapBTreeHeptaNode

A l'intérieur même d'une classe, la même norme s'applique aux types (ici des
enum) et aussi sous une autre forme (initiales du nom d'enum) aux constantes
(préfixe K):

class CmicMapBTreeHeptaNode
{
private:
enum EmicMBHNNodesTypes
{
KntHeptaNode,
KntDataNode
};
enum EmicMBHNBalanceCases
{
KbcUnused,
KbcBalanced,
KbcBendLeft,
KbcBendRight
};
enum EmicMBHNMiscFlags
{
KmfLeft,
KmfRight,
KmfBoth
};
...

Voilà l'idée.
*Loin de moi la prétention d'imposer ce type de norme à quiconque*,
mais la lourdeur est insignifiante avec un peu d'habitude,
je ne connais pas les conflits de compilation ni les mélanges de constantes
symboliques,
et surtout j'ai des tonnes de code écrit comme ça et sur lequel je reviens
(même occasionnellement) sans aucun effort de déchiffrage.

Sans pretention donc, hope it gives you ideas.

--
Cordialement.
--
* Patrick BRUNET www.ipzb.fr
* E-mail: lien sur http://zener131.eu/ContactMe
Avatar
pjb
"Patrick 'Zener' Brunet" writes:
Sur la méthode, il y en a plusieurs, selon vos goûts: c'est vous qui devez
vous y retrouver au premier coup d'oeil, puis vos lecteurs quand ils auront
saisi votre logique par ailleurs systématique.

Par exemple, si vous aviez nommé vos divers projets Jupiter, Saturne et
Pluton, vous n'auriez aucun conflit entre:
- JupFile, JupString, JupComplex, JupDynArray...
- SatFile, SatString, SatComplex...
- PluComplex... vous m'avez compris.



En C, c'est obligatoire effectivement. Plus exactement:

Jupiter_File, Jupiter_String, ...
Saturn_File, Saturn_String, ...
...

Sinon vous allez avoir des problèmes avec JupFile de la bibliothèque
Jupon et SatString de la bibliothèque Satinée.



Mais en C++ on a le choix d'utiliser les namespace, et c'est ce que
je conseille:

Jupiter::File, Jupiter::String
Saturne::File, Saturne::String.

Et même:

com::informatimago::Jupiter::File pour ne pas avoir de problème avec
name::brunet::zener::patric::Jupiter::File.

Avec les avantages suivants:

- on peut utiliser le nom non qualifié à l'intérieur du namespace,
donc ce n'est pas lourdingue partout.

- on peut définir un alias de namespace:
namespace MonJupiter = com::informatimago::Jupiter;
donc ce n'est pas lourdingue toujours.


--
__Pascal Bourguignon__
Avatar
Jean-Marc Desperrier
Pascal J. Bourguignon wrote:
- on peut définir un alias de namespace:
namespace MonJupiter = com::informatimago::Jupiter;



Est-ce que ça permet de répondre proprement à la question d'origine en
utilisant un alias "namespace N2 = ::N2" ?

Je pose la question car je ne sais pas comment tenter cela se comporte
face à N1::N2, ni surtout si ça pose un problème de récursivité.
Avatar
pjb
Jean-Marc Desperrier writes:

Pascal J. Bourguignon wrote:
- on peut définir un alias de namespace:
namespace MonJupiter = com::informatimago::Jupiter;



Est-ce que ça permet de répondre proprement à la question d'origine en
utilisant un alias "namespace N2 = ::N2" ?

Je pose la question car je ne sais pas comment tenter cela se comporte
face à N1::N2, ni surtout si ça pose un problème de récursivité.



Et bien, JNSPUADL, mais je pense que si namespace N2 = ::N2; est cité
à la racine des namespaces, c'est à dire quand N2 est effectivement
déjà identique à ::N2, alors soit ça n'aura aucun effet, soit ça
donnera un warning ou une erreur.

D'un autre côté, clairement:

#include <iostream>

namespace N2 {
const int n=2;
}

/*
namespace N3 {
namespace N2 {
const int n2;
}
namespace N2 = ::N2; // devrait produire une erreur, N2 est N3::N2
}
*/

namespace N1 {
namespace N2 {
const int n;
}
namespace N3 {
namespace N2 = ::N2;

void f(){ std::cout<<N2::n<<" "<<::N2::n<<" "<<N1::N2::n<<std::endl; }
}
}

int main(){
N1::N3::f();
return(0);
}


devrait afficher:
2 2 12

c'est à dire que dans N3, N2 et ::N2 sont identiques et différents de N1::N2.


--
__Pascal Bourguignon__
Avatar
Patrick 'Zener' Brunet
Bonsoir.

"Pascal J. Bourguignon" a écrit dans le message de
news:
"Patrick 'Zener' Brunet" writes:
> Sur la méthode, il y en a plusieurs, selon vos goûts: c'est vous
> qui devez vous y retrouver au premier coup d'oeil, puis vos lecteurs
> quand ils auront saisi votre logique par ailleurs systématique.
>
> Par exemple, si vous aviez nommé vos divers projets Jupiter,
> Saturne et Pluton, vous n'auriez aucun conflit entre:
> - JupFile, JupString, JupComplex, JupDynArray...
> - SatFile, SatString, SatComplex...
> - PluComplex... vous m'avez compris.

En C, c'est obligatoire effectivement. Plus exactement:

Jupiter_File, Jupiter_String, ...
Saturn_File, Saturn_String, ...
...

Sinon vous allez avoir des problèmes avec JupFile de la
bibliothèque Jupon et SatString de la bibliothèque Satinée.




En théorie, certes...
Mais il y a environ 26^3 trigrammes possibles de ce type (et le principe du
trigramme est arbitraire), de plus il faudrait que dans le même module, vous
"usingiez" 2 namespaces de librairies utilisant le même principe et le même
trigramme, et de plus fournissant deux classes homonymes dont vous avez
besoin...

A ce niveau c'est vraiment pas de pot, et de toute manière les namespaces ne
vous sauveraient pas, à moins de qualifier tous les identifiants que vous
utilisez, comme ci-dessous:

[...]

com::informatimago::Jupiter::File pour ne pas avoir de
problème avec
name::brunet::zener::patrick::Jupiter::File.




Alors ça dans le genre lisible :-(
Si vous faites ça pour chaque type, méthode et pour ses arguments
symboliques (et je ne parle pas d'un template), c'est strictement impossible
à indenter sans scroller horizontalement de deux pages (et donc impossible à
imprimer sur du A4 aussi).

C'est précisément l'un des facteurs d'illisibilité que je cherche à éviter.

Avec les avantages suivants:

- on peut utiliser le nom non qualifié à l'intérieur du namespace,
donc ce n'est pas lourdingue partout.




Pour le namespace en question, pas pour son concurrent, sinon le problème ne
se poserait pas.
Donc en plus la notation devient dissymétrique: toi je te qualifie, toi
c'est implicite...
Avec un maximum de copier-coller aussi pour les qualifiers... Oh la galère !
C'est un plaidoyer pour faire générer le code par les wizards UML ça :o)

- on peut définir un alias de namespace:
namespace MonJupiter = com::informatimago::Jupiter;
donc ce n'est pas lourdingue toujours.




Certes, mais si comme c'est le cas pour Korchkidu, il y a des namespaces
concurrents, je ne crois pas que définir des aliases lève le problème.

D'ailleurs, s'il y a possibilité de conflit sur les identifiants, c'est tout
aussi vrai sur les noms des namespaces... A moins d'utiliser des GUID, c'est
un problème universel et on ne peut qu'en réduire la probabilité. Reste
alors à le faire d'une manière pratique d'emploi...

Ainsi, voyez-vous, je persiste à considérer que dès lors que l'on utilise
intensivement un ou plusieurs namespaces dans un module, il est intéressant
de se donner les moyens de faire un/plusieurs using au début de ce module
pour y travailler plus simplement avec les identifiants nus.
Et pour ça, le préfixage des identifiants est très facilitateur jusqu'à un
niveau de complexité assez élevé.

Avec un bon niveau d'immunité aux conflits, et de plus un bon niveau de
reconnaissance visuelle.

Mais c'est une idée comme une autre, on a le droit de ne pas aimer :-)
Finalement je préfère si peu de gens l'adoptent, ça renforce ses qualités
pour ceux qui le font...

--
Cordialement.
--
* Patrick BRUNET www.ipzb.fr
* E-mail: lien sur http://zener131.eu/ContactMe
Avatar
Fabien LE LEZ
On Wed, 6 Aug 2008 01:01:11 +0200, "Patrick 'Zener' Brunet" :

Ainsi, voyez-vous, je persiste à considérer que dès lors que l'on utilise
intensivement un ou plusieurs namespaces dans un module, il est intéressant
de se donner les moyens de faire un/plusieurs using au début de ce module
pour y travailler plus simplement avec les identifiants nus.



Certes. Mais "using" peut s'utiliser de deux façons différentes :
using std::string;
using namespace std;

La première introduit un nom précis, "string". À chaque fois que je
tape "string" quelque part dans mon code, je suis conscient qu'il
s'agit de std::string.

La deuxième introduit plein de noms, dont je ne connais pas la moitié.
Si j'utilise le mot "greater" quelque part dans mon code, je ne serai
pas forcément conscient qu'il y a un conflit avec std::greater,
d'autant que je n'ai jamais utilisé ce dernier.

La solution la plus fiable me paraît donc d'utiliser des namespaces,
et utiliser using pour introduire les identifiants les plus
fréquemment utilisés.
1 2