OVH Cloud OVH Cloud

j'ai besoin d'aide

43 réponses
Avatar
Ghislain Tchoudjeu Ngaha
slt a tous,

je ne m'y connais pas du tout en c++ et je dois ecrire un programme qui
qui change les lettres majuscules en minuscules...Comment le faire?

3 réponses

1 2 3 4 5
Avatar
kanze
Franck Branjonneau wrote:
"kanze" écrivait:

Franck Branjonneau wrote:
"kanze" écrivait:

Franck Branjonneau wrote:
Yoxoman écrivait:






La solution avec transform serait quelque chose du
genre :

typedef std::ctype< char >
Cvt ;
std::transform(
source.begin(), source.end(),
std::back_inserter( dest ),
std::bind1st(
std::mem_fun(
static_cast< char (Cvt::*)( char ) const >(
&Cvt::tolower ) ),
&std::use_facet< Cvt >( std::locale() ) ) ) ;

Sans oublier d'initialiser le locale global avant.


Ca me fait penser à un film : Scanners. Ca parle de
gens capables de faire exploser le cerveau d'autres
presonnes à distance.


Si c'est le static_cast<> qui t'ennuie, tu peux l'enelever.


Tu en es sûr ?


Je n'ai aucune certitude.

Il y a bien deux fonctions std::ctype<>::tolower, selon
la norme. C'est vrai que la deuxième prend deux
paramètres, et qu'il n'y a aucune instantiation de
std::mem_fun qui accepte l'adresse d'une fonction à deux
paramètres.


Oui mais ce ne sont pas des fonctions templates. Ce sont
des fonctions membres d'une classe template std::ctype<>.
Qui, elle, a été instanciée avec char, le compilateur doit
donc choisir entre les deux signatures

std::ctype< char >::tolower(char) const;
std::ctype< char >::tolower(char, const char) const;

pour choisir quelle std::mem_fun<> utiliser.


C'est juste, mais je ne crois pas que ça change grand chose.


Je crois que si.

Pour déterminer les paramètres d'instantiation de
std::mem_fun<>, on se sert de la déduction des types, qui
elle ne fonctionne (je crois) qu'avec un type connu. Or,
pour connaître le type ici, il faut de la résolution du
surcharge.


Je ne suis pas sur que l'on puisse parler de résolution du
surcharge, même si ça revient au même.


Tout à fait. S'il y a une décision sur la fonction à choisir,
c'est dans la déduction des types du template que ça se passe.
Au moins dans un premier temps. (Une fois mem_fun instantiée, on
passe quand même par la phase de résolution du surcharge, pour
choisir le Cvt::tolower. Mais une fois mem_fun instantiée, il
n'y a plus qu'un surcharge de Cvt::tolower qui marche ; la
résolution est triviale, parce qu'on a déjà fait le choix
avant.)

Si j'ai bien compris la norme, la résolution du surcharge ne
se fait qu'une fois la déduction des types finie ; de toute
façon, il a besoin de l'instantiation pour faire la
résolution du surcharge.


"Résolution de surcharge" et déduction de type font parties de
la déduction des arguments templates (en particulier les
types) -- je crois que tu ne différencies pas "déduction de
type" et "déduction des arguments templates".


Oui. Je parle effectivement de la déduction des paramètres réels
des templates. (Dans le temps, on ne pouvait déduire que les
types.)

La résolution de surcharge, c'est bien une opération à part, qui
n'a lieu qu'après l'instantation des templates, et donc après la
déduction des paramètres réels des fonctions templatées. Tel que
je le comprends :

1. Le compilateur récherche le nom. Dans le cas des fonctions,
le résultat de cette récherche peut en fait être un ensemble
d'entités, et non seulement une seule.

2. Pour chaque fonction dans cet ensemble, le compilateur
ajoute la fonction à l'ensemble de surcharge.

3. Pour chaque fonction template dans l'ensemble initial, le
compilateur essaie de déterminer des paramètres
d'instantiation, avec la déduction des paramètres réels pour
les paramètres qui n'ont pas été donnés explicitement. Si la
déduction réussit, l'instantiation du template est ajouté à
l'ensemble de surcharge.

4. Le compilateur effectue la résolution du surcharge sur
l'ensemble de surcharge.

Encore tel que je l'ai compris, la déduction ne réussit que s'il
n'y a qu'une seule instantiation possible (pour la fonction
templatée en question).

Ici, la seule question en ce qui me concerne, c'est : donnée la
declaration de fonction templatée :

template< typename S, typename T, typename A >
mem_fun1_t< S, T, A > mem_fun( S (T::*)( A ) ) ;

et l'appel :

mem_fun( &Cvt::tolower ) ;

est-ce que la déduction des paramètres réels permet à trouver
(et donc instancier) une seule fonction, ou est-ce qu'elle
échoue. Il y a une deuxième surcharge de mem_fun, qui est aussi
une fonction templatée, mais là, je suis sûr que la déduction
des paramètres réels échouera. On aurait donc ou bien une seule
fonction (la déduction ci-dessus réussit) ou bien aucune
fonction dans l'ensemble de surcharge. Dans le premier cas, la
résolution du surcharge choisira cette unique fonction, ce qui
permettrait à la résolution de surcharge à bien choisir le bon
Cvt::tolower. Dans le deuxième cas, évidemment, on a une erreur.

Et j'avoue ne pas être sûr de la réponse, même avec la
norme sous les mains.

Mais tes commentaires m'ont amené a regardé dans la norme.
En fait, §14.8.2.2 dit bien que « Template arguments can be
deduced from the type specified when taking the address of
an overloaded function. »


Non, 14.8.2.2 c'est (l'emphase est mienne) « Deducing template
arguments taking the address of a function *template* ».

, et dans §14.8.2.4 :

In some cases, tye deduction is done using a single set
of types P and A. [P est le type du paramètre formel,
et A le type du paramètre réel].


in other cases, there will be a set of corresponding
types P and A.


Tout à fait. J'avoue ne pas pouvoir comprendre du tout cette
phrase. Pour la fonction en question, le P est clair : S (T::*)(
A ). Mais quels sont les A, et surtout, ici, quel est l'ensemble
qu'on va constituer : trois ensembles des paires (S,x), (T,x) et
(A,x), un seul ensemble de toutes les paires, ou quelque chose
d'autre ?

Type deduction is done independantly for each P/A pair,
and the deduced template argument values are then
combined. If type decduction cannot be done for any P/A
pair, or if for any pair the deduction leads to more
than one possible set of deduced values, or if different
pairs yield different deduced values, or if any template
argument remains neither deduced nor explicilty
specified, template argument deduction fails.

Ce qui n'est pas particulièrement clair.


L'algorithme en lui même est accessible, determiner P/A est
malaisé.


Ici, on a un P (S (T::*)( A )), et un seul A (&Cvt::lower). Sauf
que le A est ambigu en ce qui concerne le type. Est-ce qu'on le
traite comme deux A, de types char (Cvt::*)(char) const et char
const* (Cvt::*)( char* char const* ) const ? Ou est-ce qu'on
rénonce, en disant qu'on ne peut pas continuer, parce qu'on ne
connaît pas le type du seul A.

Je pars de 14.8.2.1 « Deducing template arguments from a
function call » et je cale. Aussi je saute en 14.8.2.4/16 « A
template argument can be deduced from a pointer to function or
pointer to member function argument if the set of overloaded
functions does not contain function templates and at most one
of a set of overloaded functions provides a unique match. » Ce
qui, je crois, règle le cas de std::ctype<>::tolower.


Là aussi, j'avoue ne pas pouvoir réelement comprendre la phrase.
La première partie, « the set of overloaded functions does not
contain function templates », est clair, et la condition est
remplie ici. La deuxième est plus difficile. (Et manifestement
faux -- ça doit être « exactly one », plutôt que « at most
one ». Mais il y a sans doute quelque chose que je n'ai pas
compris ici.)

Intuitivement, d'après les exemples, je crois que l'intention
est bien plus ou moins de considérer toutes les paires (P,A)
possibles, en traitant chaque surcharge de la fonction comme un
A à part. (Ce qui explique la restriction interdisant les
templates -- avec les templates, l'ensemble des A serait
infini.) On aurait donc deux paires :
(S (T::*)( A ), char (Cvt::*)( char ) const)
(S (T::*)( A ), char const* (Cvt::*)( char*, char const* ) const )
(En passant : si je vois intuitivement ce qu'il faut faire
vis-à-vis ces « const » finaux, je ne vois rien dans la norme
qui en dit quoique ce soit.)

Dès lors, tout se passe comme on veut. On a une déduction de (S
= char, T = Cvt, A = char) pour le premier, et on ne peut pas
faire la déduction avec le deuxième. (En passant : la liste dans
§14.8.2.4/9 est donnée pour exhaustive. Elle ne comporte pas de
fonction à deux paramètres. Les exemples dans §14.8.2.4/16
comportent deux paramètres. Ils sont donc faux ?)

Ça ne me plaît pas de me baser que sur les exemples, surtout des
exemples qui sont en contradiction directe avec un autre
paragraphe. Mais je n'arrive pas à comprendre le texte. Du tout.

Pour le cas de std::tolower/std::tolower<>, tu auras noté que
14.8.2.4/16 est similaire à la résolution de surcharge (dans
le sens de 13.4) avec une contrainte plus forte sur les
fonctions templates.


Il y a des ressemblances. Mais la façon de procéder est quand
même différente. Surtout, il n'y a pas de « ranking » ; si deux
surcharges marchent, c'est une erreur, point à la ligne. On ne
cherche pas à en choisir un plutôt qu'un autre. (Au moins qu'il
y a quelque chose que j'ai raté -- ce qui est fort probable --
il n'y a même pas de préférence pour un match exact.)

C'est cette contrainte qui, je crois, autorise g++-3.x (x à
voir) à rejeter

std::transform(
source.begin(), source.end(),
cible,
&::tolower)


Qu'est-ce qui peut provoquer un rejet ici ? L'ensemble de
surcharge de &::tolower comporte exactement un membre, de type
int (*)( int ). Pour le quatrième paramètre, on a donc la paire
(P,A)=(UnaryOperator,int (*) int). UnaryOperator n'apparaît dans
aucun autre paramètre formel, et aucun autre paramètre du
template n'apparaît dans le quatrième paramètre de la fonction.
La déduction est donc simple : UnaryOperator est int (*)( int ).

En supposant qu'il n'y a pas de « using namespace std ; »,
évidemment. Et que les fonctions dans <ctype.h> sont réelement
dans l'espace référentiel global. Je ne suis pas trop sûr sur
les effets d'un « using namespace » ni d'un « using » tout court
quand on a qualifié le nom comme ici.

Je note simplement que g++-4.0 compile ce code.

(C'est une analyse simpliste. Le cas pointeur sur fonction est
distinct du cas pointeur sur fonction membre, en particulier
14.8.2.4/1 prévoit des conversions sur T, A.)

Il y a bien deux analyses distinctes : la déduction des
types, et la résolution des surcharges.


Si d'une part, résolution de surcharge c'est 13.3 -- et par
extension 13.4 -- et, d'autre part, déduction des types c'est
déduction des arguments templates, alors non. L'analyse c'est
14.8.2.4/16.


Bien sûr que si.

La seule question réele, c'est le traitement de l'ensemble de
surcharge dans la déduction des paramètres réels des templates.
Je ne vois rien qui suggére qu'on effectue un choix entre les
fonctions (une résolution de surcharge). Tout au plus qu'on
considère chaque fonction surchargée comme une entité en soi.
C'est ensuite du tout ou rien -- s'il y a plus d'une fonction
qui marche, la déduction échoue, et on ne va pas plus loin.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34







Avatar
Franck Branjonneau
"kanze" écrivait:

[...]

Et j'avoue ne pas être sûr de la réponse, même avec la
norme sous les mains.


Nous sommes d'accord ;-)


Pour le cas de std::tolower/std::tolower<>, tu auras noté que
14.8.2.4/16 est similaire à la résolution de surcharge (dans
le sens de 13.4) avec une contrainte plus forte sur les
fonctions templates.


Il y a des ressemblances. Mais la façon de procéder est quand
même différente. Surtout, il n'y a pas de « ranking » ; si deux
surcharges marchent, c'est une erreur, point à la ligne. On ne
cherche pas à en choisir un plutôt qu'un autre. (Au moins qu'il
y a quelque chose que j'ai raté -- ce qui est fort probable --
il n'y a même pas de préférence pour un match exact.)


La similarité portait sur la sélection des fonctions templates.

C'est cette contrainte qui, je crois, autorise g++-3.x (x à
voir) à rejeter

std::transform(
source.begin(), source.end(),
cible,
&::tolower)



Je voulais dire std::tolower.

Je note simplement que g++-4.0 compile ce code.

(C'est une analyse simpliste. Le cas pointeur sur fonction est
distinct du cas pointeur sur fonction membre, en particulier
14.8.2.4/1 prévoit des conversions sur T, A.)

Il y a bien deux analyses distinctes : la déduction des
types, et la résolution des surcharges.


Si d'une part, résolution de surcharge c'est 13.3 -- et par
extension 13.4 -- et, d'autre part, déduction des types c'est
déduction des arguments templates, alors non. L'analyse c'est
14.8.2.4/16.


Bien sûr que si.

La seule question réele, c'est le traitement de l'ensemble de
surcharge dans la déduction des paramètres réels des templates.


C'est là que je ne suis pas d'accord : le traitement de l'ensemble de
surcharge dans la déduction des paramètres templates n'est pas une
résolution de surcharge -- on n'utilise ni 13.3, ni 13.4.

--
Franck Branjonneau



Avatar
kanze
Franck Branjonneau wrote:
"kanze" écrivait:

[...]

Il y a bien deux analyses distinctes : la déduction des
types, et la résolution des surcharges.


Si d'une part, résolution de surcharge c'est 13.3 -- et par
extension 13.4 -- et, d'autre part, déduction des types
c'est déduction des arguments templates, alors non.
L'analyse c'est 14.8.2.4/16.


Bien sûr que si.

La seule question réele, c'est le traitement de l'ensemble
de surcharge dans la déduction des paramètres réels des
templates.


C'est là que je ne suis pas d'accord : le traitement de
l'ensemble de surcharge dans la déduction des paramètres
templates n'est pas une résolution de surcharge -- on
n'utilise ni 13.3, ni 13.4.


C'est ce que j'ai cru avoir dit. Il y a deux analyses
distinctes. Ou trois, si on compte la construction de l'ensemble
de surcharge comme une analyse à part. (À vrai dire, je la
pensais comme une partie du name binding. Mais si on considère
le surcharge des opérateurs, c'est un peu plus complexe que ça.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34




1 2 3 4 5