FAQ C++ moderne et erreurs courantes

Ce ou ces sujets font partie d'une FAQ en cours d'écriture, vos retours sont les bienvenus.
Lorsque vous tentez de passer l'adresse d'une fonction (ou un objet avec un opérateur parenthèses) possédant plusieurs surcharges, vous vous heurtez irrémédiablement à votre compilateur, qui à ce moment très précis n'a aucune idée de la surcharge à sélectionner. Il vous incombe donc de l'aider dans ce choix.
Ceci sera fait grâce à l'opérateur de cast static_cast
, explicitement vers le type de la surcharge à utiliser. Exemple avec la fonction surchargée suivante :
float
square(float
value) {
return
value *
value; }
double
square(double
value) {
return
value *
value; }
Utilisation de la première surcharge :
std::vector<float> vec{1.f, 2.f, 3.f, 4.f, 5.f};
std::transform(
vec.begin(), vec.end(),
std::ostream_iterator<float>{std::cout, ", "},
static_cast<Type de retour de la fonctionfloat (*)Paramètre(s) de la fonction(float)>(square));
Depuis C++11, vous pouvez plus aisément utiliser une fonction lambda qui évitera ce problème :
std::
transform(
vec.begin(), vec.end(),
std::
ostream_iterator<
float
>{
std::
cout, ", "
}
,
[](float
value) {
return
square(value); }
);
Attention, utiliser la première solution sur une fonction de la STL qui n'est pas désignée comme « addressable function » relève dès C++20 du comportement non spécifié voire ill-formed. Cf. Addressable functions.
En particulier, vous pourrez vous heurter aux deux surcharges de la fonction std::toupper :
std::toupper dans <cctype> |
Sélectionnez
|
std::toupper dans <locale> |
Sélectionnez
|
std::
string str {
"abcdefghijklmnopqrstuvwxyz"
}
;
std::
transform(str.begin(), str.end(), str.begin(), std::
toupper);
error: no matching function for call to 'transform(std::__cxx11::basic_string<char>::iterator, std::__cxx11::basic_string<char>::iterator, std::__cxx11::basic_string<char>::iterator, <unresolved overloaded function type>)'
std::transform(str.begin(), str.end(), str.begin(), std::toupper);
Utilisation de la première surcharge :
auto to_upper = []ch est le paramètre qui sera passé par std::transform.
D'une certaine façon, nous créons la fonction to_upper suivante :
char to_upper(char ch) {
return static_cast<char>( std::toupper(static_cast<unsigned char>(ch) ) );
}(char ch) { return static_cast<char>( std::toupper( Ce cast est obligatoire afin d'éviter un comportement indéfini (cf. la partie « Notes » de la documentation).static_cast<unsigned char>(ch) ) ); };
std::transform(str.begin(), str.end(), str.begin(), to_upper);
Utilisation de la seconde surcharge :
std::locale loc(/* … */);
auto to_upper = Nous capturons la variable loc afin de pouvoir l'utiliser au sein de la fonction lambda.[loc](char ch) { return std::toupper(ch, loc); };
std::transform(str.begin(), str.end(), str.begin(), to_upper);
À voir également