On continue l’aventure Cplusplus11 après le premier article qui était plus une mise ne jambe. Cette fois-ci nous allons attaquer les fonctions anonymes, Lambda expression. Les expressions lambda sont utiles pour écrire des blocs de code en ligne qui sont des fonctions un peu spéciales. Ces fonctions anonymes peuvent être passées en paramètre d’autres fonctions et peuvent aussi récupérer le contexte comme nous le verrons plus loin. Par ailleurs les fonctions lambda améliorent aussi la lisibilité des programmes C++11 car il n’est plus nécessaire d’encapsuler des méthodes qu’on veut utiliser qu’une fois dans des classes ou des fichiers externes. C’est maintenant l’heure d’explorer la signature des Lambda expression.

Signature d’une expression lambda

[capture] (arguments) attribute-specifier mutable exception-specification -> return-type {body}
// or
[capture] (arguments) -> return-type {body}
// or
[capture] (arguments) {body}
// or
[capture] {body}

Description de la signature de l’expression lambda

capture (liste de capture)
  • [] : aucune capture des variables du contexte
  • [this] : capture le pointeur this de la classe englobante
  • [&] : capture toutes les variables du contexte par référence
  • [=] : capture toutes les variables du contexte par valeur
  • [&x] : capture uniquement la variable x par référence
  • [x] : capture uniquement la variable x par par valeur
  • [x, &y] : capture la variable x par par valeur et y par référence
arguments (liste d’arguments)
  • liste des paramètres de la fonction lambda
attribute-specifier, mutable, exception-specification (modificateur et spécificateurs)
  • attribute-specifier : [[noreturn]] indique que la fonction ne retourne rien et [[carries_dependency]] permet de contrôler la gestion du stockage en mémoire. Ne fonctionne pas avec G++ 4.6.3, actuellement seul Intel-C++ 12.1 les supportes
  • mutable : permet de modifier les variables capturées par valeur dans le corps de la fonction
  • exception-specification : spécificateur d’exception tel que noexcept, throw(), etc…
return-type
Type de retour de la fonction lambda.
body
Corps de la fonction lambda.

Exemple d’utilisation (projet github des exemples)

#include<iostream>
#include<vector>
#include<algorithm>

int main() {
	std::vector<std::string> data{"first", "second", "third"};
	std::string one = "one!!";
	std::string two = "two";
	std::string three = "three";
	std::cout << std::endl;
	// Process data vector with lambda function
	for_each(begin(data), end(data), [one, &two, &three](std::string &item) mutable {
		item  += "_append";
		one   += "_another value now"; // We use "mutable" for variable passed by copy.
		two   += "_two";
		three += "_three";
	});
	// Print data vector after processing
	std::cout << "after:" << std::endl << " - data: ";
	for (const auto d : data) {
		std::cout << d << " ";
	}
	std::cout << std::endl;
	std::cout << " - one: " << one << " - two: " << two << " - three: " << three;
	std::cout << std::endl;
	return 0;
}

Dans cet exemple nous initialisons un vecteur de string avec 3 éléments, puis nous initialisons 3 variables de type string. Nous utilisons for_each pour parcourir le vecteur data et concaténons chaque élément avec une expression lambda passée en paramètre de for_each. Dans le corps de la fonction lambda, nous concaténons aussi les variables one (récupéré par valeur), two (récupéré par référence), three (récupéré par référence). Nous affichons, au final, le résultat. Vous remarquerez que la variable one n’a pas été impactée après le traitement car elle a été capturée par valeur.

//output
after:
 - data: first_append second_append third_append
 - one: one!! - two: two_two_two_two - three: three_three_three_three

Ce sera tout pour le moment, nous attaquerons d’autres nouveautés dans un prochain article…

Je viens de recevoir mon boîtier Pibow après 1 mois et demi d’attente. Mais ce n’est qu’une étape avant de recevoir le device Raspberry Pi le mois prochain. Un conseil, soyez patient !

Photos du déballage :

Il y a quelques mois je me réjouissais de la validation du standard C++11. Je regrette toujours que les sockets réseau n’aient pas été implémenté.

Après plusieurs lectures sur le sujet, je recherche l’adoption totale de la nouvelle syntaxe de C++11. Tentons de dompter les nouveautés. Les exemples sont testés avec GCC version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3), le code source est disponible sur GitHub.

Nous allons commencer à travailler sur les types automatiques avec le mot clé auto et l’opérateur decltype.

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>//for_each
#include<typeinfo>//typeid

int main() {
  std::vector<std::string> data{"first", "second", "third"};//uniform brace notation
  for (const auto item : data) {//Range based for loop
  std::cout << "Iterate =>" << std::endl;
    std::cout << "  Automatic item type: " << typeid(item).name() << " - Item value: " << item << std::endl;
    decltype(item) dynamic_value = item;
    std::cout << "  Dynamic type: " << typeid(dynamic_value).name() << " - Dynamic value: " << dynamic_value << std::endl;
    std::cout << std::endl;
  }
  return 0;
}

Dans cet exemple nous initialisons un vecteur de chaîne de caractères puis bouclons sur chaque item ; le type de chaque item est récupéré automatiquement et nous créons dynamiquement une variable du même type que l’item. Pour le moment ne tenez pas compte de la syntaxe particulière de la boucle for.

Simplification de l’itération simple d’un conteneur avec la structure de contrôle for.

#include<iostream>
#include<vector>
#include<string>

int main() {
  std::vector<std::string> data{"first", "second", "third"};
  for(const auto item : data) {
    std::cout << "Item value: " << item << std::endl;
  }  
  return 0;
}

Une simple boucle for tel que le propose déjà des langages tel que Java ou C#. Un vrai bonheur pour notre langage. Notons que pour un parcours spécifique ou plus complexe, il est plus puissant d’utiliser for_each ; par exemple commencer l’itération à partir du 3ème élément.

Avant C++11, la macro NULL équivalente à 0, est parfois considéré comme très particulière par les développeurs et porte à confusion. C++11 propose une expression nullptr, plus d’excuses et arrêtons d’utiliser 0 ou NULL pour initialiser un pointeur.

#include<iostream>
#include<vector>

int main() {
  const int* p = nullptr;
  std::vector<int> data{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  for (const auto item : data) {
    p = &item;
    std::cout << "Item pointer: " << *p << std::endl;
  }
  return 0;
}

On initialise un pointeur avec nullptr et non 0, puis on boucle sur les données en assignant l’adresse de chaque item au pointeur p.

Uniformisation de l’initialisation avec les accolades {}. Avant C++11, selon qu’on veut initialiser un tableau, les membres d’une structures… avec des zéros ou avec des valeurs différentes de zéro, il fallait passer par des syntaxes différentes. Avec C++11 on arrête avec toutes ces possibilités, on uni formalise comme le montre le code source suivant :

#include<string>
#include<sstream>
#include<vector>

struct Version {
  uint32_t major;
  uint32_t minor;
  uint32_t revision;
  
  std::string toString() const {
    std::ostringstream oss;
    oss << major << "." << minor << "." << revision;
    return oss.str();
  }
};

int main() {
  Version v{0, 1, 0};//Constructor initialization
  std::cout << "Version v{0, 1, 0}: " << std::endl;
  std::cout << "  " << v.toString() << std::endl;
  std::vector<Version> vArray{{0, 1, 0}, {0, 1, 1}, {0, 1, 2}};//Array initialization
  std::cout << "std::vector<Version> vArray{{0, 1, 0}, {0, 1, 1}, {0, 1, 2}}: " << std::endl;
  for (const auto v : vArray) {
    std::cout << "  " << v.toString() << std::endl;
  }
  return 0;
}

On crée une instance de Version en initialisant major, minor et revision. On crée ensuite un vecteur de Version en initialisant les 3 premiers éléments.

Les nombres aléatoires, peuvent être générés selon un nouveau modèle qui se compose de deux éléments, un moteur de génération de nombre (il y en a plusieurs au choix) et une distribution soit une plage de nombre pouvant être généré, là encore on a le choix de la distribution ; voir un aperçu via ce lien.

#include<iostream>
#include<random>//std::mt19937, std::uniform_int_distribution
#include<functional>//std::bind
#include<ctime>

std::mt19937 engine;
std::uniform_int_distribution<uint32_t> distribution{1, 10};

int main() {
  engine.seed(static_cast<uint32_t>(std::time(nullptr)));
  auto generator = std::bind(distribution, engine);
  uint32_t random = generator();
  std::cout << "1st random: " << random << std::endl;
  random = generator();
  std::cout << "2nd random: " << random << std::endl;
  return 0;
}

Dans cet exemple on instancie le moteur de génération de type Mersenne Twister avec une distribution uniforme d’entier. On initialise dans la méthode main, le moteur avec un nombre entier récupérer de l’horloge de la machine. On se fabrique une fonction generator qui permet d’appeler notre générateur avec un nom plus intuitif.

Voilà c’est une première mise en jambe avec C++11 histoire de s’échauffer. Je reste persuadé du potentiel de ce langage et de son avenir glorieux. C++11 est le langage le plus concis et rapide de la planète.

J’ai acheté il y a 4 mois le smartphone Google Nexus chez Rue du Commerce, mais depuis, et je ne sais pas pourquoi, à chaque annonce de mise à jour d’Android Ice Cream Sandwich, impossible que la détection des mises à jour me propose quoique ce soit…

Finalement ce matin j’ai décidé de réaliser manuellement cette mise à jour via les outils et fichiers officiels de Google (Pas besoin de rooter le téléphone).

La première chose à faire est d’installer le SDK Android via le lien suivant (pour les connaisseurs, uniquement le binaire fastboot est suffisant) : http://developer.android.com/sdk/installing.html.

Vérifier la configuration USB du Google Nexus sur la machine en vérifiant ou créant le fichier des droits udev (seules les lignes des Google Nexus sont nécessaires mais qui sait, j’aurai peut-être le bonheur de tester d’autres Google Android devices)

chris@tux:~/tmp/yakju-imm76i$ sudo emacs /etc/udev/rules.d/51-android.rules

Copier/coller les lignes suivantes dans le fichier /etc/udev/rules.d/51-android.rules

# adb protocol on passion (Nexus One)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e12", MODE="0600", OWNER="##votre_nom_d_utilisateur##"
# fastboot protocol on passion (Nexus One)
SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", ATTR{idProduct}=="0fff", MODE="0600", OWNER="##votre_nom_d_utilisateur##"
# adb protocol on crespo/crespo4g (Nexus S)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e22", MODE="0600", OWNER="##votre_nom_d_utilisateur##"
# fastboot protocol on crespo/crespo4g (Nexus S)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e20", MODE="0600", OWNER="##votre_nom_d_utilisateur##"
# adb protocol on stingray/wingray (Xoom)
SUBSYSTEM=="usb", ATTR{idVendor}=="22b8", ATTR{idProduct}=="70a9", MODE="0600", OWNER="##votre_nom_d_utilisateur##"
# fastboot protocol on stingray/wingray (Xoom)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="708c", MODE="0600", OWNER="##votre_nom_d_utilisateur##"
# adb protocol on maguro/toro (Galaxy Nexus)
SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", ATTR{idProduct}=="6860", MODE="0600", OWNER="##votre_nom_d_utilisateur##"
# fastboot protocol on maguro/toro (Galaxy Nexus)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e30", MODE="0600", OWNER="##votre_nom_d_utilisateur##"
# adb protocol on panda (PandaBoard)
SUBSYSTEM=="usb", ATTR{idVendor}=="0451", ATTR{idProduct}=="d101", MODE="0600", OWNER="##votre_nom_d_utilisateur##"
# fastboot protocol on panda (PandaBoard)
SUBSYSTEM=="usb", ATTR{idVendor}=="0451", ATTR{idProduct}=="d022", MODE="0600", OWNER="##votre_nom_d_utilisateur##"
# usbboot protocol on panda (PandaBoard)
SUBSYSTEM=="usb", ATTR{idVendor}=="0451", ATTR{idProduct}=="d010", MODE="0600", OWNER="##votre_nom_d_utilisateur##"

On relance le service udev

chris@tux:~/tmp/yakju-imm76i$ sudo service udev restart

Télécharger et décompresser la mise à jour Factory Images « yakju » for Galaxy Nexus « maguro » (GSM/HSPA+) (pas besoin de Google Wallet en France pour la majorité d’entre nous) depuis le site de Google : https://developers.google.com/android/nexus/images?hl=fr-FR#yakju

Démarrer le Google Nexus en mode fastboot en appuyant simultanément sur les boutons : Volume+ et Volume- et PowerOnOff

Se rendre dans le répertoire où l’image à été décompressé pour débloquer le mode fastboot

chris@tux:~/tmp/yakju-imm76i$ fastboot oem unlock
...
OKAY [ 25.900s]
finished. total time: 25.900s

Lancer la mise à complète d’ICS 4.0.4

chris@tux:~/tmp/yakju-imm76i$ ./flash-all.sh
sending 'bootloader' (2308 KB)...
OKAY [  0.318s]
writing 'bootloader'...
OKAY [  0.292s]
finished. total time: 0.610s
rebooting into bootloader...
OKAY [  0.006s]
finished. total time: 0.006s
sending 'radio' (12288 KB)...
OKAY [  1.736s]
writing 'radio'...
OKAY [  1.379s]
finished. total time: 3.116s
rebooting into bootloader...
OKAY [  0.006s]
finished. total time: 0.007s
archive does not contain 'boot.sig'
archive does not contain 'recovery.sig'
archive does not contain 'system.sig'
--------------------------------------------
Bootloader Version...: PRIMELA03
Baseband Version.....: I9250XXLA2
Serial Number........: 0146B0000101601D
--------------------------------------------
checking product...
OKAY [  0.007s]
checking version-bootloader...
OKAY [  0.008s]
checking version-baseband...
OKAY [  0.008s]
sending 'boot' (4148 KB)...
OKAY [  0.577s]
writing 'boot'...
OKAY [  0.252s]
sending 'recovery' (4478 KB)...
OKAY [  0.638s]
writing 'recovery'...
OKAY [  0.310s]
sending 'system' (316111 KB)...
OKAY [ 44.125s]
writing 'system'...
OKAY [ 33.302s]
erasing 'userdata'...
OKAY [  0.315s]
erasing 'cache'...
OKAY [  0.013s]
rebooting...

finished. total time: 79.598s

Rebooter en mode fastboot pour remettre le lock par soucis de sécurité

chris@tux:~/tmp/yakju-imm76i$ fastboot oem lock
...
OKAY [  0.170s]
finished. total time: 0.170s

Je suis enfin à jour et je gagne en performance, c’est fluide !!!

Avec Ubuntu Oneiric (11.10), impossible d’installer l’application de téléchargement des mp3s d’Amazon (Amazon MP3 Downloader).
Pour cause les librairies libboost sont trop récentes et ne sont pas retrouveés dynamiquement par le programme AmazonMP3 Downloader ; je crois qu’il vaut mieux pour amazon travailler sur la compilation statique du produit. Ci-dessous les étapes pour pallier le problème (basées sur une discussion ubuntuforums) :

mkdir -p $HOME/tmp/amazonmp3_oneiric
cd $HOME/tmp/amazonmp3_oneiric

Télécharger les fichier .deb :

wget https://launchpadlibrarian.net/26959932/libboost-signals1.34.1_1.34.1-16ubuntu1_i386.deb https://launchpadlibrarian.net/26959936/libboost-thread1.34.1_1.34.1-16ubuntu1_i386.deb https://launchpadlibrarian.net/26959922/libboost-iostreams1.34.1_1.34.1-16ubuntu1_i386.deb https://launchpadlibrarian.net/26959918/libboost-filesystem1.34.1_1.34.1-16ubuntu1_i386.deb https://launchpadlibrarian.net/26959916/libboost-date-time1.34.1_1.34.1-16ubuntu1_i386.deb https://launchpadlibrarian.net/26959928/libboost-regex1.34.1_1.34.1-16ubuntu1_i386.deb https://launchpadlibrarian.net/34165098/libicu40_4.0.1-2ubuntu2_i386.deb
sudo dpkg -i lib*.deb

Télécharger et installer l’application Amazon MP3 Downloader : http://www.amazon.com/gp/dmusic/help/amd.html?ie=UTF8&forceos=Linux.
Pour l’installation, il est possible d’utiliser les détails fournis par amazon sur la page de téléchargement ou en mode console :

sudo dpkg -i AmazonMP3DownloaderInstall.deb

Et voilà.

Discussions qui traitent aussi du sujet :