OVH Cloud OVH Cloud

Position de const

60 réponses
Avatar
Jmr
Bonjour, je voudrais écrire une fonction copiant le contenu d'un tableau
dans un autre. j'utilise la déclaration suivante :

bool Cpy(const float * & Source, float * & Dest)

En espérant que :
? & Source : passe le pointeur Source à la fonction en tant que référence
pour éviter une copie inutile (mais est-ce bien nécessaire ?)
? const float : évite de modifier la valeur du pointeur Source. (const
doit-il être placé là ou plutôt ici : float * const & Source ?)

Par la suite j'utilise une fonction déclarée ainsi :

bool Affect (const Data & src, Data & dest)

où :

Data est du genre :
struct Data
{
int n ;
float *p ;
} ;

Lorsque j'écris :
bool Affect (const Data & src, Data & dest)
{
Cpy(src.p, dest.p) ;
..
}

le compilateur affiche l'erreur suivante : error C2664: 'Cpy' : cannot
convert parameter 1 from 'float *const ' to 'const float *& '

j'en déduis que les qualificatifs const sont mal placés mais où faut'il les
placer ?

Par avance Merci

10 réponses

2 3 4 5 6
Avatar
Fabien LE LEZ
On Mon, 22 Sep 2003 17:36:52 +0200, Xavier Hardy
wrote:

Dans le même ordre d'idée, faudrait-il alors écrire
"int unsigned const i = 1;" ?


Non : "unsigned" et "const" ne sont pas du tout comparables.

--
Let's face it, boys: the Trash Heap _is_ all.
-- the Trash Heap, Fraggle Rock, ep 1

Avatar
Gabriel Dos Reis
Fabien LE LEZ writes:

| On Mon, 22 Sep 2003 17:36:52 +0200, Xavier Hardy
| wrote:
|
| >Dans le même ordre d'idée, faudrait-il alors écrire
| >"int unsigned const i = 1;" ?
|
| Non : "unsigned" et "const" ne sont pas du tout comparables.

et alors ?

-- Gaby
Avatar
kanze
Gabriel Dos Reis wrote in message
news:...
Samuel Krempp writes:

| > comme "unsigned int typedef size t" ?

| ça encore, on peut répondre que c'est particulier, typedef

Hmm. Donc vous avez la r gle compl tement fausse. La r gle g n ra le
est que les d clarations se lisent innermost to outermost .

que dire de

void (*f(int (&)[8]))(const int&)

?


C'est trop simple. Il y a des parenthèses:-).

Mais au fond, je suis d'accord avec toi. Une déclaration en C++, c'est
en fait un espèce d'expression, et elle ne se comprend et ne s'écrit que
comme une expression, avec une connaissance des priorités des opérateurs
et avec des parenthèses. Et il faut savoir où la spécification de la
declaration termine et les declarateurs commencent. (C'est drôle, mais
pour comprendre le langage, il faut connaître le langage.)

Donc, dans ton cas, en commençant avec ce qu'on déclare (f), c'est une
fonction, parce que le (int (&)[8]) a précédence sur le *. Une fonction
qui renvoie un pointeur (le *). Et c'est un pointeur à une fonction,
parce qu'une fois de plus, les (const int&) ont précédance sur le
declarateur.

Le type du paramètre de la fonction est plus difficile, parce qu'il n'y
a pas le nom de ce qu'on déclare pour donner le point de départ. Mais en
fait, le seul endroit où on pouvait mettre un nom sans que ce soit une
erreur, c'est après le & : int (&param)[8]. Donc, c'est une référence à
un tableau de 8 int.

Je sais que de temps en temps, les gens ont essayé à présenter des
règles plus simples, du genre de gauche à droit, ou de l'intérieur vers
l'extérieur. Chaque fois, il s'avère qu'il y avait des exceptions, où ça
ne marchait pas. Déjà avec ta règle :
void (*f( int (&p1)[8]))(int const& p2) ;
Si je commence à l'« innermost », je commence avec p1 ou p2, pas avec f,
ce qui est faux (parce que c'est bien f que je définis. Et la règle
laisse en suspence le cas où il y a plusieurs choses au même niveau :
void (*f( int *(&p1)[8] ))( int const& ) ;
Lequel est plus à l'intérieur, le * ou le [8]. (En revanche, selon la
grammaire de l'expression, le [8] a une précédence supérieur. Donc, pas
d'ambigüité.)

Certains préconcise l'utilisation libérale des typedef pour gérer les
précédences et éviter le problème. Je ne suis pas tout à fait convaincu.
Considérons quelque chose comme :

static bool (C1::* (C2::*const table[])( std::string const& ))() {
// ...
} ;

(Il m'est réelement arrivé d'utiliser une construction semblable une ou
deux fois.)

C'est vrai que si j'écrivais plutôt :

typedef bool (C1::*PtrFncC1)() ;
typedef PtrFncC1 (C2::* PtrFncC2)( std::string const& ) ;
static PtrFncC2 const table[] {
} ;

Ça a l'air bien plus simple. En revanche, c'est bien sur le premier que
je dois me baser pour écrire :

found = (myC2.*(this->*(table[i]))( s ))() ;

Cacher la complexité ne l'élimine pas.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Avatar
Gabriel Dos Reis
writes:

| Gabriel Dos Reis wrote in message
| news:...
| > Fabien LE LEZ writes:
|
| > | On Mon, 22 Sep 2003 17:36:52 +0200, Xavier Hardy
| > | wrote:
|
| > | >Dans le même ordre d'idée, faudrait-il alors écrire
| > | >"int unsigned const i = 1;" ?
|
| > | Non : "unsigned" et "const" ne sont pas du tout comparables.
|
| > et alors ?
|
| Les motivations pour mettre le const après ce qu'il modifie ne
| s'applique pas à unsigned. Si je fais :
| typedef int I ;
| ni :
| unsigned I i ;
| ni :
| I unsigned i ;
| ne sont légaux.

Tu as trouvé ça où ?

Pour les autres, l'assertion de James est en flagrante contradiction avec
les paragraphes 7.1/2 et 7.1/3 de ce qui, jusqu'à nouveau désordre,
définit C++.

[...]

| Maintenant, est-ce que tu accepteras également « int extern unsigned » ?
| Voire même « int unsigned const extern » ?

si je dois accepter « int const », pourquoi ne pas accepter d'autres
avatards ?

-- Gaby
Avatar
Gabriel Dos Reis
writes:

| Gabriel Dos Reis wrote in message
| news:...
| > Samuel Krempp writes:
|
| > | > comme "unsigned int typedef size t" ?
|
| > | ça encore, on peut répondre que c'est particulier, typedef
|
| > Hmm. Donc vous avez la r gle compl tement fausse. La r gle g n ra le
| > est que les d clarations se lisent innermost to outermost .
|
| > que dire de
|
| > void (*f(int (&)[8]))(const int&)
|
| > ?
|
| C'est trop simple. Il y a des parenthèses:-).

[...]

| Je sais que de temps en temps, les gens ont essayé à présenter des
| règles plus simples, du genre de gauche à droit, ou de l'intérieur vers
| l'extérieur. Chaque fois, il s'avère qu'il y avait des exceptions, où ça
| ne marchait pas. Déjà avec ta règle :
| void (*f( int (&p1)[8]))(int const& p2) ;

yep, c'est pour cela que je l'ai donné en commençant pas
« que dire de ... ».

| Si je commence à l'« innermost », je commence avec p1 ou p2, pas avec f,
| ce qui est faux (parce que c'est bien f que je définis. Et la règle
| laisse en suspence le cas où il y a plusieurs choses au même niveau :
| void (*f( int *(&p1)[8] ))( int const& ) ;
| Lequel est plus à l'intérieur, le * ou le [8]. (En revanche, selon la
| grammaire de l'expression, le [8] a une précédence supérieur. Donc, pas
| d'ambigüité.)
|
| Certains préconcise l'utilisation libérale des typedef pour gérer les
| précédences et éviter le problème. Je ne suis pas tout à fait convaincu.
| Considérons quelque chose comme :
|
| static bool (C1::* (C2::*const table[])( std::string const& ))() | {
| // ...
| } ;
|
| (Il m'est réelement arrivé d'utiliser une construction semblable une ou
| deux fois.)
|
| C'est vrai que si j'écrivais plutôt :
|
| typedef bool (C1::*PtrFncC1)() ;
| typedef PtrFncC1 (C2::* PtrFncC2)( std::string const& ) ;
| static PtrFncC2 const table[] | {
| } ;
|
| Ça a l'air bien plus simple. En revanche, c'est bien sur le premier que
| je dois me baser pour écrire :
|
| found = (myC2.*(this->*(table[i]))( s ))() ;
|
| Cacher la complexité ne l'élimine pas.

100% d'accord.

-- Gaby
Avatar
Gabriel Dos Reis
writes:

| légal comme simple-type-specifier. En fait, pour savoir ce qui est
| permis dans un simple-type-specifier, il faut regarder dans §7.1.5.2
| (section qui s'appelle « Simple type specifiers » -- qui l'aurait cru),

nous sommes en train de parler de « decl-specifier » et non de
« simple-type-specifier ». Et pour savoir ce qui est permis dans un
decl-specifier, il faut regarder dans 7.1 qui porte le nom de
« specifer » -- qui l'eut cru ?.

[...]

| > | Maintenant, est-ce que tu accepteras également « int extern unsigned
| > | » ? Voire même « int unsigned const extern » ?
|
| > si je dois accepter « int const », pourquoi ne pas accepter d'autres
| > avatards ?
|
| Peut-être parce que tu n'es pas seul au monde,

si je ne suis pas seul au monde, alors il est presque certain que toi
non plus tu n'es pas seul au monde et si je dois accepter
« int const », je ne vois aucune raison de ne pas accepter les autres
avatards.

| et que d'autres auraient éventuellement à travailler sur ton code ?

oui, et cela veut dire que je ne dois pas accepter les autres avatards
si j'acceptes « int const » ?

| Personne n'en discute la légalité.

Alors pourquoi tu écris cette phrase ? Pour remplir ton message qui
aurait été vide sinon ? Très certainement, parce que plus haut tu
discutes de « légalité ».

| On ne parle pas ici de ce qu'on peut faire, mais de ce qu'on
| doit faire.

c'est qui « on » ?

Ce que je fais dans mon code est certainement différent de ce que les
autres font dans leurs codes. Dans mon propre code, j'utilise de
manière cohérente « const T ». À partir du moment où je dois accepter
des formes variantes, je considère que je dois accepter d'autres
avatards. C'est une règle que j'adapte à l'environnement.
Avatar
Xavier Hardy
On Tue, 23 Sep 2003 09:08:58 -0700, kanze wrote:
Du point de vue de la grammaire, pourtant, « typedef » est un « storage
class specifier », exactement comme static ou extern. (De la grammaire
seulement ; nous savons tous qu'il a une autre sémantique.)
[...]
Parmi les « specifiers » en C++, on a :


Merci pour toutes ces précisions. Je devrais sans doute lire
les normes plus souvent...

[...]
cv qualifiers (const, volatile)


Pourquoi « cv » ? Est-ce un nom ad hoc pour regrouper const
et volatile, formé par leurs initiales ?

Dans le C++ réformé de mes fantasmes, on écrirait ça ainsi :
double(double)* f;


Moi, je préfèrerais :

function * f( d : inout double ) returns x : double ;

ou quelque chose de ce genre. Tant que faire. Mais alors, je ferais que
l'affectation soit une instruction, et non un opérateur, et je
supporterai les affectations multiples. Disons :

variable x : double ;
variable y : double ;
function f( a : in double )
returns x : double, y : double
{
x := 2 * a ;
y := 3 * a ;
}

x, y := y, x ; // Pas besoin d'une fonction swap.
x, y = f( x, y ) ;

M'enfin, je ne crois pas qu'un nom comme C++ conviendrait au
resultat:-).


Effectivement, il faudrait mieux l'appeler Pascal/Ada++.
Sans doute la jeunesse qui refait surface ^_^.

Mon idée (sans doute idiote) est en fait de garder le plus
possible ce qui fait la saveur de la syntaxe du C/C++ et
sa brièveté, c'est-à-dire les accolades, le = pour l'affec-
tation, le type avant la variable, etc. En revanche, j'aime
bien l'idée de l'affectation multiple, la virgule servirait
alors de constructeur de tuples. On pourrait alors avoir
des déclaration de fonctions comme ceci :

int, int (int, int) eucldiv;

Maintenant, il faudrait trouver une syntaxe agréable pour la
définition de la fonction. (Comment placer les paramètres
formels ?...)

De même pour les tableaux :

double[] da;


Tu n'aurais pas fait du Java ?


En fait, non. Je me disais bien que cette syntaxe me rappelait
quelque chose.

Pourquoi pas :
variable da : array [] of double ;


Plus de trente lettres contre une douzaine...
C'est sûr que l'information est mieux mise en évidence,
mais c'est un exemple de verbosité que les tenants de
la syntaxe C/C++ ont toujours rejeté, non ?

Une chose est certaine, si j'avais quelque chose à changer en C++, sans
tenir compte de l'histoire (et donc de la compatibilité C), je ferais
que les declarations commencent par un mot clé, pour qu'il ne puisse
jamais avoir d'ambigüité entre ce qui est une declaration et ce qui est
une expression. Parce que cette ambigüité, c'est vraiment ce qu'il y a
de pire en C++.


Certes, mais je ne pense pas qu'il y ait besoin pour cela
de mots-clés.

Et pour une fois, je ne crois pas que je suis un outsider dans mon point
de vue. Je crois qu'il y en a d'autres à qui la syntaxe actuelle des
declarations ne plaît pas particulièrement.


Des noms !

On abandonne donc la tradition du (et donc la compatibilité avec le)
C


Et voilà où le bat blesse. Au départ, c'est (en partie au moins) la
compatibilité C qui a assuré la réussite de C++. Et maintenant, c'est
la réussite (c-à-d la quantité de code existant) qui rend un
changement difficile --


Disons qu'avec ce genre d'argument, aucune réforme ne serait
jamais entreprise, car il y a toujours un existant à préserver.
C'est d'ailleurs un existant précédent qui avait justifié
le choix de la compatibilité avec le C.

Quoiqu'il en soit, dans le cas qui nous occupe, la philosophie
du « aussi proche que possible du C, mais pas trop » est ce
qui a fait l'esprit et le succès du C++. Ceux qui ne sont pas
d'accord peuvent aller apprendre un des nombreux autres langages
existant fondé sur une autre approche.

rendre illégal quelque chose comme :
int i ;
n'est pas près à être adopté.


D'ailleurs je me garderais bien de le proposer ! Je tiens à la vie.

où la délaration singe l'usage. Ce qui permet de déclarer sans trop
se casser la tête un tableau de deux pointeurs constants sur des
fonctions qui prennent des doubles et renvoient des doubles :

double(double) * const [2] f_pt_a = { fptr1, fptr2 }; Je ne veux même
pas essayer de savoir comment on peut faire ça en C/C++...


typedef double (*PtrFnc)( double ) ;
PtrFnc const f_pt_a[] = { fptr1, fptr2 } ;

voire :

double (*const f_pt_a[ 2 ])( double ) = { fptr1, fptr2 } ;

C'est assez simple, en fait :


Oui, en fait, mais je n'ai pas eu ni le temps, ni le courage, ni
les connaissances pour fabriquer un exemple réellement compliqué.

En revanche, ça montre une faille dans l'histoire de
typedef/post-position du const. Dans :

typedef double (MaClasse::*PtrMemFnc)( double ) ;
PtrMemFnc const f ;

c'est bien le pointeur qui est const, et non la fonction, ce qui serait
le cas si on écrivait :

double (MaClasse::*f)( double ) const ;

Mais dès que le nom de ce qu'on declare se trouve à l'intérieur de la
declaration, il faut un peu de vrai analyse. Typedef ou non.


Dans ma syntaxe, cela donnerait :

typedef MaClasse:: double(double) * PtrMemFnc ;
PtrMemFnc const f ;
MaClasse:: double(double) const * f ;

Pas moyen de se tromper, je crois, car la lecture se fait intégralement
de droite à gauche.


Avatar
kanze
Xavier Hardy wrote in message
news:...
On Tue, 23 Sep 2003 09:08:58 -0700, kanze wrote:
Du point de vue de la grammaire, pourtant, « typedef » est un «
storage class specifier », exactement comme static ou extern. (De la
grammaire seulement ; nous savons tous qu'il a une autre
sémantique.)
[...]
Parmi les « specifiers » en C++, on a :


Merci pour toutes ces précisions. Je devrais sans doute lire les
normes plus souvent...

[...]
cv qualifiers (const, volatile)


Pourquoi « cv » ? Est-ce un nom ad hoc pour regrouper const et
volatile, formé par leurs initiales ?


Tout à fait. Depuis, le C a ajouté « restricted », et parle de « type
qualifiers ».

Dans le C++ réformé de mes fantasmes, on écrirait ça ainsi :
double(double)* f;


Moi, je préfèrerais :

function * f( d : inout double ) returns x : double ;

ou quelque chose de ce genre. Tant que faire. Mais alors, je ferais
que l'affectation soit une instruction, et non un opérateur, et je
supporterai les affectations multiples. Disons :

variable x : double ;
variable y : double ;
function f( a : in double )
returns x : double, y : double
{
x := 2 * a ;
y := 3 * a ;
}

x, y := y, x ; // Pas besoin d'une fonction swap.
x, y = f( x, y ) ;

M'enfin, je ne crois pas qu'un nom comme C++ conviendrait au
resultat:-).


Effectivement, il faudrait mieux l'appeler Pascal/Ada++. Sans doute la
jeunesse qui refait surface ^_^.


La jeunesse, ou le bon sens, je ne sais pas lequel.

Mon idée (sans doute idiote) est en fait de garder le plus possible ce
qui fait la saveur de la syntaxe du C/C++ et sa brièveté, c'est-à-dire
les accolades,


Pas de problème là, voir l'exemple.

Mais ça se discute si on adopte une syntaxe Algol 68 (Modula-3, et je
crois Ada). Le problème avec cette syntaxe, c'est qu'il n'y pas toujours
une ouverture explicite -- c'est le then de l'if ou le do de while ou de
for qui ouvre un bloc. Apparamment, aussi, il y aurait des avantages à
utiliser des end différents selon le type de bloc, du genre :

if ( condition ) then statements endif ;
while ( condition ) do statements enddo ;

etc.

Mais je n'ai pas un fort avis sur la question.

le = pour l'affectation,


Intuitivement, je verrais = pour la comparaison, et donc quelque chose
d'autre (:=, <-, etc.) pour l'affectation. Mais là non plus, je n'ai pas
d'avis très fort. L'importance, pour que l'affectation multiple
fonction, c'est que l'affectation ne soit pas un opérateur comme les
autres. Ce qui est un grand écart par rapport à la famille C.

le type avant la variable,


Mais c'est là précisement la source du problème.

En fait, il serait souhaitable que le type d'instruction soit
reconnaissable du premier token, ou au moins, à partir d'un nombre fini
de tokens au début de l'instruction. Sinon, il faut du backtracking dans
le parser, et ça pose également des problèmes d'ambigüité pour les
hommes.

Évidemment, on pourrait considérer quelque chose du genre :
var int x ;

etc. En revanche, j'aime bien l'idée de l'affectation multiple, la
virgule servirait alors de constructeur de tuples.


Un problème, en partant de C++, c'est que la virgule dans cette contexte
est déjà un opérateur -- une expression du genre « x, y = y, x » est
parfaitement légale dans le C++ aujourd'hui, avec une sémantique bien
définie. L'affectation multiple changerait donc la sémantique d'un
programme légal.

On pourrait alors avoir des déclaration de fonctions comme ceci :

int, int (int, int) eucldiv;

Maintenant, il faudrait trouver une syntaxe agréable pour la
définition de la fonction. (Comment placer les paramètres formels
?...)


J'avoue que j'allais plus loin. Les valeurs de rétour d'une fonction,
c'était des variables prédéfinies dans la fonction. Il n'y avait pas de
return (ni de break, ni de goto, ni de continue).

De même pour les tableaux :

double[] da;


Tu n'aurais pas fait du Java ?


En fait, non. Je me disais bien que cette syntaxe me rappelait quelque
chose.

Pourquoi pas :
variable da : array [] of double ;


Plus de trente lettres contre une douzaine...


Plus facile à lire. Alors, tu écris un programme une fois, mais il sera
lu une multitude de fois. Il faut donc priviléger la lecture.

Et puis, le nombre de caractères était bien un argument quand on
travaillait avec ed, sur un télétyp. Mais aujourd'hui, franchement. Avec
un clavier moderne et un écran, et un éditeur modern avec les
abbréviations et l'achévemment automatique des mots...

Il ne faut pas oublier non plus que pour peu qu'on sait tapper (ce que
doit savoir tout programmeur), on tappe des lettres jusqu'à dix fois
plus vite que les caractères spéciaux. Je sais qu'il me faut moins de
temps à tapper « begin » que de tapper un « { ». Et je parle encore d'un
clavier US -- avec un clavier français, c'est pire. (Or que tu veux bien
des accents dans les commentaires, n'est-ce pas.)

C'est sûr que l'information est mieux mise en évidence, mais c'est un
exemple de verbosité que les tenants de la syntaxe C/C++ ont toujours
rejeté, non ?


Historiquement, il y avait de bons motifs pour le rejeter : si tu as
déjà travaillé sur un vrai télétyp, à 10 caractères par séconde, et un
véritable « clunk » à chaque caractère, tu comprendrais pourquoi on
voulait minimiser le nombre des caractères. Mais aujourd'hui -- c'est
priviléger l'auteur (une personne) par rapport aux lecteurs (nombreux).

Une chose est certaine, si j'avais quelque chose à changer en C++,
sans tenir compte de l'histoire (et donc de la compatibilité C), je
ferais que les declarations commencent par un mot clé, pour qu'il ne
puisse jamais avoir d'ambigüité entre ce qui est une declaration et
ce qui est une expression. Parce que cette ambigüité, c'est vraiment
ce qu'il y a de pire en C++.


Certes, mais je ne pense pas qu'il y ait besoin pour cela de
mots-clés.


La grande question : quand tu vois une instruction qui commence par :
MaClasse, est-ce que c'est une declaration, ou une expression ?

En C, le problème était moindre : il fallait écrire « struct MaStruct ».
Il n'y avait alors que les typedef pour poser un problème.

Et pour une fois, je ne crois pas que je suis un outsider dans mon
point de vue. Je crois qu'il y en a d'autres à qui la syntaxe
actuelle des declarations ne plaît pas particulièrement.


Des noms !


Il serait plus difficile à trouver des noms des personnes qui trouvent
que la syntaxe actuelle est une réussite. Je crois que c'est Stroustrup
lui même qui a caractèrisé la syntaxe des declarations en C comme « une
expérience qui a échouée » (ou quelque chose du genre).

Et considère l'instruction ultra-connue :

std::vector< double > v( std::istream_iterator< double >( src ),
std::istream_iterator< double >() ) ;

A priori, on voulait définir un vecteur initialisé en lisant des valeurs
de src. En fait, on a déclaré une fonction v qui renvoie un vector, et
qui prend deux paramètres, un istream_iterator, et un pointeur à une
fonction qui renvoie un istream_iterator.

Plusieurs (dont Stroustrup, je crois, mais je ne suis pas sûr) ont
caractèrisé ceci comme un embarras. Or, si la déclaration d'une variable
commencait par un mot clé (disons variable ou var), l'ambigüité
disparaîtrait, et l'instruction ferait ce qu'on s'y attendait.

On abandonne donc la tradition du (et donc la compatibilité avec
le) C


Et voilà où le bat blesse. Au départ, c'est (en partie au moins) la
compatibilité C qui a assuré la réussite de C++. Et maintenant,
c'est la réussite (c-à-d la quantité de code existant) qui rend un
changement difficile --


Disons qu'avec ce genre d'argument, aucune réforme ne serait jamais
entreprise, car il y a toujours un existant à préserver.


Régarde du côté C. Ils ont ajouté plusieurs nouveautés dans C99, sans
casser grand chose.

Dans la pratique, il y a toujours des compromis à faire, et on prend
bien la risque de casser quelques programmes. Mais on veut que le nombre
en soit faible. Ce qui ne serait certainement pas le cas si on se
mettait à exiger que toute declaration commence par un mot clé nouveau.
(Ceci dit, je crois qu'il en y a plusieurs qui étudient la question. On
continuerait sûrement à supporter l'ancienne syntaxe, mais il y aurait
une nouvelle syntaxe à côté.)

C'est d'ailleurs un existant précédent qui avait justifié le choix de
la compatibilité avec le C.

Quoiqu'il en soit, dans le cas qui nous occupe, la philosophie du
«@aussi proche que possible du C, mais pas trop » est ce qui a fait
l'esprit et le succès du C++. Ceux qui ne sont pas d'accord peuvent
aller apprendre un des nombreux autres langages existant fondé sur une
autre approche.


La philosophie, c'était « aussi proche du C que possible, mais pas
plus ». La question a toujours été : qu'est-ce qui fait « plus » ? Et
les avis diffèrent. Dès le départ, Stroustrup a introduit une
incompatibilité majeur ; il fallait declarer les fonctions avant
l'utilisation, et en spécifiant leur paramètres. (Le C a adopté la
solution C++ par la suite, mais elle reste facultative, même
aujourd'hui.)

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16



Avatar
Gabriel Dos Reis
writes:

| > le = pour l'affectation,
|
| Intuitivement, je verrais = pour la comparaison, et donc quelque chose
| d'autre (:=, <-, etc.) pour l'affectation. Mais là non plus, je n'ai pas

ah,la syntaxe. Au moins un sujet où tout le monde semble convaincu de
dire quelque chose de fondé.

je verrais = pour initialisation et rien d'autre.

| d'avis très fort. L'importance, pour que l'affectation multiple
| fonction, c'est que l'affectation ne soit pas un opérateur comme les
| autres. Ce qui est un grand écart par rapport à la famille C.
|
| > le type avant la variable,
|
| Mais c'est là précisement la source du problème.
|
| En fait, il serait souhaitable que le type d'instruction soit
| reconnaissable du premier token, ou au moins, à partir d'un nombre fini
| de tokens au début de l'instruction.

c'est le cas en C++ <g>.

| Sinon, il faut du backtracking dans
| le parser, et ça pose également des problèmes d'ambigüité pour les
| hommes.
|
| Évidemment, on pourrait considérer quelque chose du genre :
| var int x ;

c'est vrai que les gens aiment les mot clés pour faire des greps.

i : int

ne nécessite comme mot-clé que « : ». Mais il y a fort à parier qu'il
servira déjà de séparateur/ponctuateur.

Oh, j'irai même à proposer le lispesque

:i int;

ou [:i int] ou [i : int]


[...]

| Il ne faut pas oublier non plus que pour peu qu'on sait tapper (ce que
| doit savoir tout programmeur), on tappe des lettres jusqu'à dix fois
| plus vite que les caractères spéciaux. Je sais qu'il me faut moins de
| temps à tapper « begin » que de tapper un « { ». Et je parle encore d'un

tout programmeur C++ digne de ce nom sait taper { 20 fois plus que que
begin. <g>

[...]

| Et considère l'instruction ultra-connue :
|
| std::vector< double > v( std::istream_iterator< double >( src ),
| std::istream_iterator< double >() ) ;
|
| A priori, on voulait définir un vecteur initialisé en lisant des valeurs
| de src. En fait, on a déclaré une fonction v qui renvoie un vector, et
| qui prend deux paramètres, un istream_iterator, et un pointeur à une
| fonction qui renvoie un istream_iterator.
|
| Plusieurs (dont Stroustrup, je crois, mais je ne suis pas sûr) ont
| caractèrisé ceci comme un embarras.

nous avons proposé une syntaxe alternative et espérons qu'avec le
temps, elle sera plus populaire.


| Or, si la déclaration d'une variable
| commencait par un mot clé (disons variable ou var), l'ambigüité
| disparaîtrait, et l'instruction ferait ce qu'on s'y attendait.

l'ambiguité peut disparaître aussi sans mot clé.

[...]

| Régarde du côté C. Ils ont ajouté plusieurs nouveautés dans C99, sans
| casser grand chose.

Après on peut aimer le résultat ou pas. Nous sommes un certain nombre
à penser que les machins _xxx ou __xxx sont une abomination.

[...]

| (Ceci dit, je crois qu'il en y a plusieurs qui étudient la question. On
| continuerait sûrement à supporter l'ancienne syntaxe, mais il y aurait
| une nouvelle syntaxe à côté.)

j'ai proposé de mettre les mots-clés dans un namespace (std, ou autre).
évidemment, il y a ceux qui sont contre, ceux qui sont pour, ceux qui
s'en foutent, ceux qui n'ont pas d'opinion. Il faudrait probablement
au moins une dizaine d'années pour que les plus avancés fassent le saut.

-- Gaby
Avatar
Jean-Marc Bourguet
Gabriel Dos Reis writes:

| En fait, il serait souhaitable que le type d'instruction soit
| reconnaissable du premier token, ou au moins, à partir d'un nombre fini
| de tokens au début de l'instruction.

c'est le cas en C++ <g>.


J'ai l'impression que James voulait dire borné :-)

| Sinon, il faut du backtracking dans le parser, et ça pose
| également des problèmes d'ambigüité pour les hommes.
|
| Évidemment, on pourrait considérer quelque chose du genre :
| var int x ;

c'est vrai que les gens aiment les mot clés pour faire des greps.

i : int

ne nécessite comme mot-clé que « : ». Mais il y a fort à parier qu'il
servira déjà de séparateur/ponctuateur.


A part l'introduction de definition, tu vois quel usage (ok, ?:)>

Oh, j'irai même à proposer le lispesque

:i int;

ou [:i int] ou [i : int]


[...]

| Il ne faut pas oublier non plus que pour peu qu'on sait tapper (ce que
| doit savoir tout programmeur), on tappe des lettres jusqu'à dix fois
| plus vite que les caractères spéciaux. Je sais qu'il me faut moins de
| temps à tapper « begin » que de tapper un « { ». Et je parle encore d'un

tout programmeur C++ digne de ce nom sait taper { 20 fois plus que que
begin. <g>


entre CTRL-U 20 { et begin, je sais ce que je prefere. :-)

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

2 3 4 5 6