J'ai essayé le code de cette question C++ std :: transform () et toupper () ..pourquoi cela échoue-t-il?
#include <iostream>
#include <algorithm>
int main() {
std::string s="hello";
std::string out;
std::transform(s.begin(), s.end(), std::back_inserter(out), std::toupper);
std::cout << "hello in upper case: " << out << std::endl;
}
Théoriquement, cela aurait dû fonctionner car c'est l'un des exemples dans le livre de Josuttis, mais il ne compile pas http://ideone.com/aYnfv .
Pourquoi le CCG s'est-il plaint:
no matching function for call to ‘transform(
__gnu_cxx::__normal_iterator<char*, std::basic_string
<char, std::char_traits<char>, std::allocator<char> > >,
__gnu_cxx::__normal_iterator<char*, std::basic_string
<char, std::char_traits<char>, std::allocator<char> > >,
std::back_insert_iterator<std::basic_string
<char, std::char_traits<char>, std::allocator<char> > >,
<unresolved overloaded function type>)’
Est-ce que j'ai râté quelque chose? Est-ce un problème lié à GCC?
Utilisez simplement ::toupper
au lieu de std::toupper
. Autrement dit, toupper
défini dans l'espace de noms global, au lieu de celui défini dans std
espace de noms.
std::transform(s.begin(), s.end(), std::back_inserter(out), ::toupper);
Son fonctionnement: http://ideone.com/XURh7
Raison pour laquelle votre code ne fonctionne pas: il existe une autre fonction surchargée toupper
dans l'espace de noms std
qui pose problème lors de la résolution du nom, car le compilateur n'est pas en mesure de décider à quelle surcharge vous faites référence , lorsque vous passez simplement std::toupper
. C'est pourquoi le compilateur dit unresolved overloaded function type
dans le message d'erreur, qui indique la présence de surcharge (s).
Donc, pour aider le compilateur à résoudre la surcharge correcte, vous devez lancer std::toupper
as
(int (*)(int))std::toupper
Autrement dit, les éléments suivants fonctionneraient:
//see the last argument, how it is casted to appropriate type
std::transform(s.begin(), s.end(), std::back_inserter(out),(int (*)(int))std::toupper);
Vérifiez vous-même: http://ideone.com/8A6iV
std::transform(
s.begin(),
s.end(),
std::back_inserter(out),
std::toupper
);
pas de fonction correspondante pour l'appel à ‘
transform(__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::back_insert_iterator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)
’
Il s'agit d'une erreur trompeuse; la partie intéressante n'est pas qu'il n'y a "pas de fonction de correspondance" pour l'appel, mais pourquoi il n'y a pas de fonction de correspondance.
Le pourquoi est que vous passez une référence de fonction d'un "<unresolved overloaded function type>
" Comme argument, et GCC préfère l'erreur sur le appeler plutôt que sur cet échec de résolution de surcharge.
Tout d'abord, vous devez considérer comment la bibliothèque C est héritée en C++. <ctype.h>
A une fonction int toupper(int)
.
C++ hérite de ceci:
[n3290: 21.7/1]:
Les tableaux 74, 75, 76, 77, 78 et 79 décrivent les en-têtes<cctype>
,<cwctype>
,<cstring>
,<cwchar>
,<cstdlib>
(Conversions de caractères) et<cuchar>
, Respectivement.
[n3290: 21.7/2]:
Le contenu de ces en-têtes doit être le même que celui des en-têtes standard de la bibliothèque C<ctype.h>
,<wctype.h>
,<string.h>
,<wchar.h>
Et<stdlib.h>
Et l'en-tête C Unicode TR<uchar.h>
, Respectivement [..]
[n3290: 17.6.1.2/6]:
Les noms définis en tant que fonctions en C doivent être définis en tant que fonctions dans la bibliothèque standard C++.
Mais l'utilisation de <ctype.h>
Est déconseillée:
[n3290: C.3.1/1]:
Pour la compatibilité avec la bibliothèque C standard, la bibliothèque standard C++ fournit les 18 en-têtes C (D.5), mais leur utilisation est déconseillée en C++.
Et la façon d'accéder au C toupper
est via l'en-tête de compatibilité descendante C++ <cctype>
. Pour ces en-têtes, le contenu est déplacé ou copié (selon votre implémentation) dans l'espace de noms std
:
[n3290: 17.6.1.2/4]:
[..] Dans la bibliothèque standard C++, cependant, les déclarations (à l'exception des noms définis comme macros en C) sont dans la portée de l'espace de noms (3.3.6) de l'espace de noms std. Il n'est pas spécifié si ces noms sont d'abord déclarés dans la portée de l'espace de noms global puis injectés dans l'espace de noms std par des déclarations explicites d'utilisation (7.3.3).
Mais la bibliothèque C++ introduit également un nouveau modèle de fonction spécifique aux paramètres régionaux dans l'en-tête <locale>
, C'est-à-dire également appelé toupper
(bien sûr, dans l'espace de noms std
):
[n3290: 22.2]:
[..]template <class charT> charT toupper(charT c, const locale& loc);
[..]
Ainsi, lorsque vous utilisez std::toupper
, Vous avez le choix deux surcharges. Comme vous n'avez pas indiqué à GCC la fonction que vous souhaitez utiliser, la surcharge ne peut pas être résolue et votre appel à std::transform
Ne peut pas être terminé.
Maintenant, l'OP de cette question d'origine n'a pas rencontré ce problème. Il n'avait probablement pas la version locale de std::toupper
Dans le champ d'application, mais là encore, vous n'aviez pas non plus #include <locale>
!
Pourtant:
[n3290: 17.6.5.2]:
Un en-tête C++ peut inclure d'autres en-têtes C++.
Il se passe donc juste ce qui se passe que votre <iostream>
Ou votre <algorithm>
, Ou les en-têtes que ces en-têtes incluent, ou les en-têtes que ces en-têtes incluent (etc), conduisent à l'inclusion de <locale>
dans votre implémentation.
Il existe deux solutions à cela.
Vous pouvez fournir une clause de conversion pour contraindre le pointeur de fonction à faire référence à la surcharge que vous souhaitez utiliser:
std::transform(
s.begin(),
s.end(),
std::back_inserter(out),
(int (*)(int))std::toupper // specific overload requested
);
Vous pouvez supprimer la version locale de l'ensemble de surcharge en utilisant explicitement le global toupper
:
std::transform(
s.begin(),
s.end(),
std::back_inserter(out),
::toupper // global scope
);
Cependant, rappelez-vous que la disponibilité ou non de cette fonction dans <cctype>
N'est pas spécifiée ([17.6.1.2/4]
) Et l'utilisation de <ctype.h>
Est déconseillée ([C.3.1/1]
).
Ce n'est donc pas l'option que je recommanderais.
(Remarque: Je méprise l'écriture des crochets angulaires comme s'ils faisaient partie des noms d'en-tête - ils font partie de la syntaxe #include
, Pas des noms d'en-tête - mais je l'ai fait ici par souci de cohérence avec FDIS cite; et, pour être honnête, il est plus clair ...)