Bonjour à tous,
Dans le cadre de mes recherches sur le C++, après avoir étudié les classes vector, array, string, le concept de conteneur, d'itérateur, d'algorithmes et j'en passe ; je viens de m'attaquer à l'utilisation des fonctions dites "LAMBDA".
En simplifiant à l'extrême, elles constituent des fonctions potentiellement anonymes destinées à être utilisées pour des opérations locales. Elles permettent d'écrire des prédicats personnalisés dans le cadre de l'utilisation des algorithmes. C'est du moins ce que je comprends à ce stade de mes lectures.
Dans le cadre de mon apprentissage, j'écris du code C++ sous CodeBlocks que je retranscris systématiquement sur l'IDE arduino (carte : DOIT ESP32 DEV KIT V1) en version C++ moderne puis en version classique.
Par exemple dans le cadre de la création d'un programme ayant pour but d'extraire les nombres impairs d'un tableau dynamique, j'utilise l'algorithme find_if
prenant pour paramètre une fonction lambda mais au lieu de l'utiliser directement dans cet algorithme, j'en fais une variable :
#include <algorithm>
#include <vector>
using namespace std;
vector<int> const nombres {
2, 4, 6, 8 , 10, 11 , 13, 16, 17, 19, 21
};
void setup() {
Serial.begin(115200);
}
void loop() {
// déclaration itérateur
auto iterateur {begin(nombres)}; //déclaration de l'itérateur sur le premier élément du tableau nombres
// déclaration fonction lambda
auto lambda {[](int nombre) -> bool {
return nombre % 2 != 0; // renvoie nombres impairs
}};
do
{
iterateur = find_if(iterateur, end(nombres), lambda);
if (iterateur != end(nombres))
{
Serial.print( "nombre impair : ");
Serial.println( *iterateur);
++iterateur;
}
} while (iterateur != end(nombres));
Serial.print("\n");
delay(10000);
}
Dans un code classique, on peut écrire entre autre le code suivant :
int nombres[] = { 2, 4, 6, 8 , 10, 11 , 13, 16, 17, 19, 21};
size_t taille = sizeof nombres / sizeof * nombres;
int * const ptrDebut = nombres;
int * const ptrFin = nombres + taille;
// itérateur
int *it = ptrDebut;
void setup() {
Serial.begin(115200);
}
void loop() {
for (int *iterateur = it; iterateur < ptrFin ; ++iterateur) {
if (*iterateur % 2 != 0) {
Serial.print( "nombre impair : ");
Serial.println(*iterateur);
}
}
Serial.print("\n");
delay(10000);
}
Là où ça se corse c'est lorsque je veux utiliser une fonction lambda avec un tableau dynamique et la classe string
. Dans ce cas précis le code C++ dit moderne a pour seul but d'imprimer dans le moniteur série un tableau de tableau ou tableau à 2 dimensions. En langage classique ça peut donner ça :
char *const chaines[] {
"un mot",
"autre chose",
"du blabla",
"du texte",
"des lettres"
};
void setup() {
Serial.begin(115200);
}
void loop() {
for (auto &p : chaines) {
Serial.println(p);
}
delay(10000);
}
En C++ moderne version CodeBlocks ça donne :
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<string> const chaines {
"un mot",
"autre chose",
"du blabla",
"du texte",
"des lettres"
};
for_each(begin(chaines),end(chaines),
[](string const & message) -> void
{
cout << "message recu : " << message << endl;
});
return 0;
}
Par contre sur arduino en version C++ moderne ça plante :
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
vector<string> const chaines {
"un mot",
"autre chose",
"du blabla",
"du texte",
"des lettres"
};
void setup() {
Serial.begin(115200);
}
void loop() {
for_each(begin(chaines),end(chaines),
[](string const & message) -> void
{
Serial.print(message);
});
delay(10000);
}
Message d'erreur :
Arduino : 1.8.19 (Windows 10), Carte : "DOIT ESP32 DEVKIT V1, 80MHz, 921600, None, Disabled"
D:\Utilisateur\Documents\Arduino\CPP_Lambda_1\CPP_Lambda_1.ino: In lambda function:
CPP_Lambda_1:25:36: error: no matching function for call to 'HardwareSerial::print(const string&)'
Serial.print(message);
^
In file included from C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Stream.h:26,
from C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Arduino.h:167,
from sketch\CPP_Lambda_1.ino.cpp:1:
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:81:12: note: candidate: 'size_t Print::print(const __FlashStringHelper*)'
size_t print(const __FlashStringHelper *);
^~~~~
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:81:12: note: no known conversion for argument 1 from 'const string' {aka 'const std::__cxx11::basic_string<char>'} to 'const __FlashStringHelper*'
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:82:12: note: candidate: 'size_t Print::print(const String&)'
size_t print(const String &);
^~~~~
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:82:12: note: no known conversion for argument 1 from 'const string' {aka 'const std::__cxx11::basic_string<char>'} to 'const String&'
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:83:12: note: candidate: 'size_t Print::print(const char*)'
size_t print(const char[]);
^~~~~
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:83:12: note: no known conversion for argument 1 from 'const string' {aka 'const std::__cxx11::basic_string<char>'} to 'const char*'
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:84:12: note: candidate: 'size_t Print::print(char)'
size_t print(char);
^~~~~
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:84:12: note: no known conversion for argument 1 from 'const string' {aka 'const std::__cxx11::basic_string<char>'} to 'char'
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:85:12: note: candidate: 'size_t Print::print(unsigned char, int)'
size_t print(unsigned char, int = DEC);
^~~~~
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:85:12: note: no known conversion for argument 1 from 'const string' {aka 'const std::__cxx11::basic_string<char>'} to 'unsigned char'
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:86:12: note: candidate: 'size_t Print::print(int, int)'
size_t print(int, int = DEC);
^~~~~
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:86:12: note: no known conversion for argument 1 from 'const string' {aka 'const std::__cxx11::basic_string<char>'} to 'int'
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:87:12: note: candidate: 'size_t Print::print(unsigned int, int)'
size_t print(unsigned int, int = DEC);
^~~~~
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:87:12: note: no known conversion for argument 1 from 'const string' {aka 'const std::__cxx11::basic_string<char>'} to 'unsigned int'
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:88:12: note: candidate: 'size_t Print::print(long int, int)'
size_t print(long, int = DEC);
^~~~~
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:88:12: note: no known conversion for argument 1 from 'const string' {aka 'const std::__cxx11::basic_string<char>'} to 'long int'
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:89:12: note: candidate: 'size_t Print::print(long unsigned int, int)'
size_t print(unsigned long, int = DEC);
^~~~~
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:89:12: note: no known conversion for argument 1 from 'const string' {aka 'const std::__cxx11::basic_string<char>'} to 'long unsigned int'
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:90:12: note: candidate: 'size_t Print::print(long long int, int)'
size_t print(long long, int = DEC);
^~~~~
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:90:12: note: no known conversion for argument 1 from 'const string' {aka 'const std::__cxx11::basic_string<char>'} to 'long long int'
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:91:12: note: candidate: 'size_t Print::print(long long unsigned int, int)'
size_t print(unsigned long long, int = DEC);
^~~~~
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:91:12: note: no known conversion for argument 1 from 'const string' {aka 'const std::__cxx11::basic_string<char>'} to 'long long unsigned int'
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:92:12: note: candidate: 'size_t Print::print(double, int)'
size_t print(double, int = 2);
^~~~~
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:92:12: note: no known conversion for argument 1 from 'const string' {aka 'const std::__cxx11::basic_string<char>'} to 'double'
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:93:12: note: candidate: 'size_t Print::print(const Printable&)'
size_t print(const Printable&);
^~~~~
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:93:12: note: no known conversion for argument 1 from 'const string' {aka 'const std::__cxx11::basic_string<char>'} to 'const Printable&'
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:94:12: note: candidate: 'size_t Print::print(tm*, const char*)'
size_t print(struct tm * timeinfo, const char * format = NULL);
^~~~~
C:\Users\Utilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32/Print.h:94:12: note: no known conversion for argument 1 from 'const string' {aka 'const std::__cxx11::basic_string<char>'} to 'tm*'
exit status 1
no matching function for call to 'HardwareSerial::print(const string&)'
Voilà, je me demande si l'utilisation de la classe <string>
avec la classe <vector>
n'est pas à l'origine de ce plantage ?
PS : Comprenez bien qu'il ne s'agit pas pour moi de vous montrer ma science. Non, vous voyez bien sûr qu'elle est encore énormément limitée ! J'ai volontairement donné tous les détails car ça me permet de conceptualiser tout ce que j'apprends d'autant plus que le passage du C++ format CodeBlocks au C++ moderne et classique format arduino est une gymnastique intellectuelle qui me déstabilise lourdement mais que je m'impose. J'ai besoin d'en passer par là pour synthétiser toutes ces informations !
Merci par avance.