Héritage conditionnel

19/02/2008 at 00:40 - [FR]

J'ai eu comme exercice au labo a déterminer comment faire de l'héritage conditionnel en C++. Conditionnel signifiant ayant une condition, j'ai compris un booléen. Certaines personnes m'ont demande d'expliquer ca :

Pour l'exercice, afin de comprendre, j'utilise trois classes :

Evidemment, Bottom herite de l'une des deux autres, selon une condition.

Voici le code correspondant aux deux classes du dessus :

  1. # include <iostream>
  2.  
  3. class TopLeft
  4. {
  5. protected:
  6.     TopLeft()
  7.     {
  8.         std::cout << "top left" << std::endl;
  9.     }
  10. };
  11.  
  12. class TopRight
  13. {
  14. protected:
  15.     TopRight()
  16.     {
  17.         std::cout << "top right" << std::endl;
  18.     }
  19. };

Jusque la rien de méchant. Ensuite pour faire l'héritage conditionnel, j'utilise un trait . Un trait est une notion permettant un abstraction totale vis-a-vis des types, et est défini dans une classe prévue a cet effet. J'ai nomme ce trait Selector pour les besoins de l'exercice. Voici le code correspondant :

  1. template<bool C, typename T, typename U>
  2. struct Selector
  3. {
  4.     typedef T type;
  5. };
  6.  
  7. template<typename T, typename U>
  8. struct Selector<false, T, U>
  9. {
  10.     typedef U type;
  11. };

Ici, je définis donc une classe templatée Selector , que je spécialise juste en dessous dans le cas ou le booléen passé en premier paramètre vaut false . Selon la spécialisation, je définis le type type comme étant soit le 2e paramètre, soit le 3e.

Il ne reste plus qu'a faire la classe Bottom :

  1. template<bool B>
  2. class Bottom: public Selector<B, TopLeft, TopRight>::type
  3. {
  4. public:
  5.     typedef Selector<B, TopLeft, TopRight>::type parent;
  6.  
  7.     Bottom()
  8.         : parent()
  9.     {
  10.     }
  11. };

Je définis les deux types du dessus pour l'héritage, et je ne garde donc que le booléen B comme paramètre important a définir lors de l'appel :

  1. int main()
  2. {
  3.     new Bottom<1 == 1>();
  4.     new Bottom<1 == 0>();
  5. }

Ce qui renvoie bien :

>./a.out
top left
top right

Ce type d'héritage multiple est rarement utilise, mais c'est un bon petit exercice pour débuter l'apprentissage de la spécialisation de templates.

Petite expression rationnelle

17/02/2008 at 10:56 - [FR]

@(?:(?:".*?[^\\]")|(?:'.*?[^\\]')|(?:`.*?[^\\]`))|(?:\#((?:(?:".*?[^\\]")|(?:'.*?[^\\]')|
(?:`.*?[^\\]`)|[^"'`])+?)\#)@

omfg.png

Ceci est une petite expression rationnelle PERL que j'ai construit hier avec Quentin alors qu'on travaillait sur une bibliothèque SQL pour notre moteur web. Nous devions matcher tout bloc de code compris entre les tokens '#' et '#', mais ne pas compter les '#' qui apparaitraient dans des strings (et ce a l'intérieur ou a l'extérieur des blocs '# ... #'), sachant qu'une string est entourée de quotes, double-quotes ou backquotes, qui peuvent contenir ces mêmes caractères backslashés.

Par exemple, ceci devait matcher :

texte avant #une 'pomme\'verte#ou rouge' a croquer# texte après

et renvoyer :

une 'pomme\'verte#ou rouge' a croquer

En effet, le diese du milieu est dans une string, qui va de "pomme" à "rouge" , et ne doit pas être compté comme caractère de fin de bloc.

Voici le code php qui nous a permis de créer cette expression :

  1. $spl = "(?:'.*?[^\\\\]')"; // string between simple quotes
  2. $dbl = '(?:".*?[^\\\\]")'; // string between double quotes
  3. $bck = '(?:`.*?[^\\\\]`)'; // string between back quotes
  4. $string = $spl.'|'.$dbl.'|'.$bck; // a string block
  5. $diese = '\#((?:'.$string.'|[^"\'`])+?)\#'; // a # ... # block
  6. preg_match_all('@(?:'.$string.')|(?:'.$diese.')@', $content, $matches, PREG_OFFSET_CAPTURE);

Sympa, non ?

MySQL ne demarre pas automatiquement sous Mac OSX

13/02/2008 at 14:11 - [FR]

J'ai depuis quelques mois un ordinateur Macintosh (un MacBook pour les intéressés) et je souhaite évidemment travailler dessus. Parmi mes besoins, il y a MySQL. Seulement, le package d'installation fait n'importe quoi au niveau du démarrage automatique de MySQL...

A titre indicatif, il s'agit dans mon cas de la version 5.0.51, même si ce problème a l'air d'affecter de plus anciennes versions.

En effet, on peut lire dans la documentation que le package MySQLStartupItem.pkg doit installer son contenu dans /Library/StartupItems/MySQLCOM , ce qui permet au système de démarrer automatiquement le serveur MySQL. Seulement, après installation, il n'y a rien dans /Library/StatupItems qui puisse ressembler a un dossier MYSQLCOM .

Le fait est que le programme copie bizarrement le dossier dans /usr/local . Il suffit donc de le déplacer :

> sudo mv /usr/local/MySQLCOM /Library/StartupItems
Password:

Puis il ne reste plus qu'a lancer le serveur.

> sudo /Library/StartupItems/MySQLCOM/MySQLCOM start
Starting MySQL database server

PHP, file_put_contents et permission denied ?

11/02/2008 at 16:30 - [FR]

J'ai récemment découvert quelques comportements étranges de PHP. Entre autres, j'ai eu affaire a une série de "permission denied" particulièrement persistante, lorsque je voulais enregistrer des fichiers ou créer des dossiers. Pour éviter que ce problème rende chauve d'autres que moi, voici l'explication :

Tout d'abord, posons les points sur les i, voici la liste des idioties que je n'ai PAS faites :

Mais alors pourquoi encore ces warnings persistants ?

L'erreur a été de mettre dans un destructeur de classe une écriture de fichier (et accessoirement une création de dossier) et de laisser l'objet en question se détruire tout seul lors de la sortie du script. PHP trouve cela suspect, et envoie un joli warning !

La solution est de détruire soi même manuellement l'objet incrimine avec une affectation a null pour faire disparaitre ce warning encombrant.

Voici un petit code explicatif :

  1. class Test
  2. {
  3.   public function __construct()
  4.   {
  5.   }
  6.  
  7.   public function __destruct()
  8.   {
  9.     file_put_contents('test.txt', 'tralala');
  10.   }
  11. }
  12.  
  13. $test = new Test();

Ceci provoque :

Warning: file_put_contents(test.txt) [function.file-put-contents]: failed to open stream: Permission denied in test.php on line 9

Pour éviter le souci, donc, il faut ajouter cette dernière ligne a la fin du script :

$test = null;

...et le warning disparait !

February 08

1