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

What is the type of std::toupper? (Gabriel Dos Reis)

6 réponses
Avatar
Aurélien REGAT-BARREL
Bonjour,
Je suis tombé là dessus:
http://www-sop.inria.fr/galaad/personnel/gdr/C++/talks/type-of-toupper.pdf

Le code d'exemple:
#include <cctype> // int std::toupper(int)
#include <algorithm> // std::transform
#include <iostream> // std::cout
#include <ostream> // operator<<
int main()
{
char s[] = "tokra";
std::transform(&s[0], &s[0] + 5, &s[0],
std::toupper);
std::cout << s << std::endl;
}
l'erreur de compilation:
error: no matching function for call to `transform(char*, char*, char*,
<unknown type>)'

Je pense avoir saisi le problème, encore que je pige pas pourquoi VC++ 7.1
ne bronche pas.
J'ai quand même du mal à suivre, surtout la solution finale proposée.
Alors j'ai 2 petites questions:
- Est-ce un problème spécifique à g++ ?
- j'ai remarqué que le g++ se plaint si on met "std::toupper" ou "toupper",
mais si on fait référence au namespace global "::toupper" ça passe. Est-ce
une bonne solution de contournement ?
Merci.

--
Aurélien REGAT-BARREL

6 réponses

Avatar
kanze
Aurélien REGAT-BARREL wrote:

Je suis tombé là dessus:

http://www-sop.inria.fr/galaad/personnel/gdr/C++/talks/type-of-toupper.pdf


Le code d'exemple:
#include <cctype> // int std::toupper(int)
#include <algorithm> // std::transform
#include <iostream> // std::cout
#include <ostream> // operator<<
int main()
{
char s[] = "tokra";
std::transform(&s[0], &s[0] + 5, &s[0],
std::toupper);
std::cout << s << std::endl;
}
l'erreur de compilation:
error: no matching function for call to `transform(char*, char*,
char*,

<unknown type>)'

Je pense avoir saisi le problème, encore que je pige pas
pourquoi VC++ 7.1 ne bronche pas.


C'est une question de la qualité de l'implémentation:-).

Selon la norme, une implémentation peut inclure d'autres
en-têtes standard dans n'importe quel en-tête
standard. Dans une bonne implémentation, l'inclusion d'un
en-tête ne rendra visibles que ce qui doit être défini dans cet
en-tête. Mais ce n'est pas facile, et aucune implémentation n'y
arrive complètement. Ici, ce qui s'est passé, c'est qu'un des
en-têtes que tu as donné a inclu <locale> dans l'implémentation
g++ ; aucun ne l'a inclu dans l'implémentation VC++.

J'ai quand même du mal à suivre, surtout la solution finale
proposée.

Alors j'ai 2 petites questions:
- Est-ce un problème spécifique à g++ ?


Oui et non ? Le problème n'a rien de spécifique à g++, dans la
mésure que l'implémentation g++ est bien conforme à cet égard.
En revanche, il s'agit bien de profiter d'une liberté permise
par la norme, et non de quelque chose obligatoire. Selon
l'implémentation, alors, le problème peut se présenter, comme il
ne peut pas se présenter.

- j'ai remarqué que le g++ se plaint si on met "std::toupper"
ou "toupper", mais si on fait référence au namespace global
"::toupper" ça passe. Est-ce une bonne solution de
contournement ?


Dans la mésure qu'aucun compilateur aujourd'hui n'est conforme.
Avec simplement ::toupper, ça ne doit pas passer, selon la
norme. (Mais c'est peut-être une erreur dans la norme ; être
conforme à cet égard est assez difficile, et n'apporte
vraisemblablement que peu.)

Si tu remplaces <cctype> par <ctype.h>, la solution avec
::toupper devient conforme, et probablement portable.

Note cependant que si tu remplaces la chaîne constante ici par
une chaîne lue de l'extérieur, le programme qui en résulte a
probablement un comportement indéfini. C'est un deuxième
problème ; si Gaby n'en a pas parlé dans l'exposé que tu cites,
c'est qu'il n'avait pas d'importance par rapport au problème
dont il parlait. (Et je me tais du problème plus général, que la
transformation toupper sur place est impossible dans le cas
général, parce qu'il n'y a pas de bijection entre les
minuscules et les majuscules.)

--
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
Aurélien REGAT-BARREL
Je pense avoir saisi le problème, encore que je pige pas
pourquoi VC++ 7.1 ne bronche pas.


C'est une question de la qualité de l'implémentation:-).

Selon la norme, une implémentation peut inclure d'autres
en-têtes standard dans n'importe quel en-tête
standard. Dans une bonne implémentation, l'inclusion d'un
en-tête ne rendra visibles que ce qui doit être défini dans cet
en-tête. Mais ce n'est pas facile, et aucune implémentation n'y
arrive complètement. Ici, ce qui s'est passé, c'est qu'un des
en-têtes que tu as donné a inclu <locale> dans l'implémentation
g++ ; aucun ne l'a inclu dans l'implémentation VC++.


Effectivement <locale> n'est pas inclus, mais ça ne suffit pas. Si je
l'inclut (avec <cctype>) ça marche quand même. Si j'inclus seulement
<locale> sans <cctype> alors là "c'est bon" il râle:
impossible de déduire l'argument de modèle de 'T2' à partir de 'char
*__w64 '
impossible d'utiliser le modèle de fonction '_Elem
std::toupper(_Elem,const std::locale &)' comme argument de fonction

En fait je trouve ça normal que ça passe : vu que y'a 2 surcharges de dispo
et que l'une d'entre elle (non template en plus, donc privilégiée dans la
recherche non ?) fonctionne, je pige pas pourquoi g++ se plaint.

- j'ai remarqué que le g++ se plaint si on met "std::toupper"
ou "toupper", mais si on fait référence au namespace global
"::toupper" ça passe. Est-ce une bonne solution de
contournement ?


Dans la mésure qu'aucun compilateur aujourd'hui n'est conforme.
Avec simplement ::toupper, ça ne doit pas passer, selon la
norme. (Mais c'est peut-être une erreur dans la norme ; être
conforme à cet égard est assez difficile, et n'apporte
vraisemblablement que peu.)

Si tu remplaces <cctype> par <ctype.h>, la solution avec
toupper devient conforme, et probablement portable.




Ah oui j'avais pas fait gaffe à ce détail.

Note cependant que si tu remplaces la chaîne constante ici par
une chaîne lue de l'extérieur, le programme qui en résulte a
probablement un comportement indéfini. C'est un deuxième
problème ; si Gaby n'en a pas parlé dans l'exposé que tu cites,
c'est qu'il n'avait pas d'importance par rapport au problème
dont il parlait. (Et je me tais du problème plus général, que la
transformation toupper sur place est impossible dans le cas
général, parce qu'il n'y a pas de bijection entre les
minuscules et les majuscules.)


Par comportement indéfini, tu fais allusion à l'histoire des majuscules /
minuscules dans certaines langues comme l'allemand ?

Merci.

--
Aurélien REGAT-BARREL



Avatar
Aurélien REGAT-BARREL
- j'ai remarqué que le g++ se plaint si on met "std::toupper"
ou "toupper", mais si on fait référence au namespace global
"::toupper" ça passe. Est-ce une bonne solution de
contournement ?




Bon ben en fait je pige plus rien car sans :: (toupper tout court) ça marche
aussi.
std::transform(&s[0], &s[0] + 5, &s[0], toupper);

D'après ce que je sais, c'est grâce au Koenig Lookup. Toujours d'apres ce
que je sais, le Koenig Lookup c'est comme si j'avais écris:
std::transform(&s[0], &s[0] + 5, &s[0], std::toupper);
car transform est dans std::
Sauf que là y'en a un qui compile et pas l'autre :/

--
Aurélien REGAT-BARREL



Avatar
Jean-Marc Bourguet
"Aurélien REGAT-BARREL" writes:

- j'ai remarqué que le g++ se plaint si on met "std::toupper"
ou "toupper", mais si on fait référence au namespace global
"::toupper" ça passe. Est-ce une bonne solution de
contournement ?




Bon ben en fait je pige plus rien car sans :: (toupper tout court) ça marche
aussi.
std::transform(&s[0], &s[0] + 5, &s[0], toupper);

D'après ce que je sais, c'est grâce au Koenig Lookup. Toujours d'apres ce
que je sais, le Koenig Lookup c'est comme si j'avais écris:
std::transform(&s[0], &s[0] + 5, &s[0], std::toupper);
car transform est dans std::


Non. L'ADL ca permet de chercher une fonction appelée avec un nom non
qualifié dans les namespaces des types des arguments, pas quelque
chose de mal défini en sens inverse.

A+

--
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




Avatar
kanze
Aurélien REGAT-BARREL wrote:
Je pense avoir saisi le problème, encore que je pige pas
pourquoi VC++ 7.1 ne bronche pas.


C'est une question de la qualité de l'implémentation:-).

Selon la norme, une implémentation peut inclure d'autres
en-têtes standard dans n'importe quel en-tête standard. Dans
une bonne implémentation, l'inclusion d'un en-tête ne rendra
visibles que ce qui doit être défini dans cet en-tête. Mais
ce n'est pas facile, et aucune implémentation n'y arrive
complètement. Ici, ce qui s'est passé, c'est qu'un des
en-têtes que tu as donné a inclu <locale> dans
l'implémentation g++ ; aucun ne l'a inclu dans
l'implémentation VC++.


Effectivement <locale> n'est pas inclus, mais ça ne suffit
pas. Si je l'inclut (avec <cctype>) ça marche quand même.


Alors, je ne comprends pas trop. Avec <locale>, il doit bien y
avoir trop de fonctions toupper.

Si j'inclus seulement <locale> sans <cctype> alors là "c'est
bon" il râle:
impossible de déduire l'argument de modèle de 'T2' à partir de
'char

*__w64 '
impossible d'utiliser le modèle de fonction '_Elem
std::toupper(_Elem,const std::locale &)' comme argument de fonction

En fait je trouve ça normal que ça passe : vu que y'a 2
surcharges de dispo et que l'une d'entre elle (non template en
plus, donc privilégiée dans la recherche non ?) fonctionne, je
pige pas pourquoi g++ se plaint.


Il y a bien plus de deux toupper disponible ; il y en a
infinies. (Tous les instantiations possibles du template.)

[...]
Note cependant que si tu remplaces la chaîne constante ici
par une chaîne lue de l'extérieur, le programme qui en
résulte a probablement un comportement indéfini. C'est un
deuxième problème ; si Gaby n'en a pas parlé dans l'exposé
que tu cites, c'est qu'il n'avait pas d'importance par
rapport au problème dont il parlait. (Et je me tais du
problème plus général, que la transformation toupper sur
place est impossible dans le cas général, parce qu'il n'y a
pas de bijection entre les minuscules et les majuscules.)


Par comportement indéfini, tu fais allusion à l'histoire des
majuscules / minuscules dans certaines langues comme
l'allemand ?


Non. Ça, c'était mon parenthèse ; ça fait que le résultat est
mauvais, même quand on évite le comportement indéfini. Le
comportement indéfini, c'est parce que tu passes un char (donc,
une valeur potentiellement négative) à la version C de toupper
(qui elle exige que son paramètre soit ou dans l'intervale
[0...UCHAR_MAX], ou EOF).

Voyons donc où on en est :

-- le code ne compile pas sur certains compilateurs (mais bien
sur d'autres),

-- ayant résolu ce problème, on tombe sur un cas de
comportement indéfini, et

-- ayant éliminé le comportement indéfini, il s'avère que le
résultat est faux.

C'est beau, le C++:-).

--
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
Aurélien REGAT-BARREL
Ok merci à vous.

--
Aurélien REGAT-BARREL