• Save
C++ Metaprogramming : multidimensional typelist
Upcoming SlideShare
Loading in...5
×
 

C++ Metaprogramming : multidimensional typelist

on

  • 2,349 views

use c++ metaprogramming to manage typelist and how build multi-dimensionnal typelist

use c++ metaprogramming to manage typelist and how build multi-dimensionnal typelist

Statistics

Views

Total Views
2,349
Views on SlideShare
2,346
Embed Views
3

Actions

Likes
1
Downloads
0
Comments
0

1 Embed 3

https://si0.twimg.com 3

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

C++ Metaprogramming : multidimensional typelist C++ Metaprogramming : multidimensional typelist Presentation Transcript

  • MetaProgrammation C++ type list multidimmensionnelle Vincent Agnus, Institut de Recherche contre les Cancers de l'Appareil Digestif Developer Forum 4 18 septembre 2008 Strasbourg University of Strasbourg, France
  • Présentation  MetaProgrammation C++  Typelist & Dispatcher  Discussion Vincent Agnus 3/50
  • Meta Programmation C++  Meta Programmation = « génération par le compilateur d'algorithmes dans le code source »  Language compilé : C++, Curl, D, Eiffel, Haskell, ML and XL.  Language interprété : modifiable pdt runtime  C++ MetaProgrammation : basée sur les templates Vincent Agnus 4/50
  • Meta Programmation C++ Template  Permet de définir des fonctions génériques --> comportement commun #include <iostream> template <typename T> inline const T& maximum(const T& x,const T& y) { if(y > x) return y; else return x; } int main(void) { // template instanciation std::cout << maximum<int>(3,7) << endl; //outputs 7 std::cout << maximum(3, 7) << endl; //same as above std::cout << maximum(3.2,7.3) << endl; //outputs 7.3 return 0; } Vincent Agnus 5/50
  • Template C++  Spécialisation de templates --> comportement particulier #include <iostream> #include <string> template<> inline const std::string& maximum(const std::string& x,const std::string& y) { if( y.size() > x.size() ) return y; else return x; } int main(void) { std::cout << maximum<int>(3,7) << endl; //sortie 7 std::string s1(''court''); std::string s2(''trestreslong''); std::cout << maximum(s1, s2) << endl; // sortie trestreslong return 0; } Vincent Agnus 6/50
  • Meta Programmation C++ Template  Classe gérant des types/valeurs génériques template<typename T> class MyVector { ... protected : int m_nbElements; T *m_elements; }; template<typename T, int N> // ici un template du genre valeur class MyArray { ... protected : T[N] m_elements; }; Vincent Agnus 7/50
  • Meta Programmation C++ Template  Les templates lors de la compilation génèrent du code temporaire qui est inséré dans le code source qui est recompilé  Metaprogrammation à partir des templates  Génération de classes à la compilation  Optimisation de code à la compilation  Définition de nouveaux idioms Vincent Agnus 8/50
  • Meta Programmation C++ Template  Génération de classe int factoriel(int n) { return (n==0?1:n*factoriel(n-1)); } void foo() { // 4 est connu au moment de la compilation int y = factoriel(4); // valeur calculée à chaque l'exécution !!! } Vincent Agnus 9/50
  • Meta Programmation C++ Template  Génération de classe template <int N> struct Factoriel { enum { value = N * Factoriel<N - 1>::value }; }; template <> struct Factoriel<0> { enum { value = 1 }; }; int factoriel(int n) { return (n==0?1:n*factoriel(n-1)); } void foo() { int x = Factoriel<4>::value; //== 24 constante générée lors de la compilation int y = factoriel(4); // valeur calculée lors de l'exécution } Vincent Agnus 10/50
  • Meta Programmation C++ Template  Optimisation de Code template<class T, int N> class MyArray { typedef MyArray<T,N> Self; Self &operator+=(const Self& rhs) { for (int i = 0; i < N; ++i) { m_elements[i] += rhs.value[i]; } // N connu => boucle déroulable return *this; } protected : T[N] m_elements; };  Compilatation : myArrayInstance += myArrayInstance2;  N connu lors de la compilation  le compilateur peut dérouler la boucle  Créer du code parallélisable Vincent Agnus 11/50
  • Meta Programmation C++ Template  Créer des idioms  Exemple «Polymorphisme statique» ou «Curiously Recurring Template Pattern» template <typename DERIVED> struct base { // ... }; struct derived : base<derived> { // ... };  Objectif :  Ajout de fonctionnalités à une classe  Dérivation sans utilisation de table de virtualité Vincent Agnus 12/50
  • Meta Programmation C++ Template  Curiously Recurring Template Pattern--Polymorphisme statique template <class DERIVED> struct Base { void interface() { // ... static_cast<DERIVED*>(this)->implementation(); // ... } static void static_func() { // ... Derived::static_sub_func(); // ... } }; struct Derived : Base<Derived> { void implementation(); static void static_sub_func(); }; Vincent Agnus 13/50
  • Meta Programmation C++ Template  Curiously Recurring Template Pattern-- exemple 1 template <typename T> struct counter class X : counter<X> { { counter() // ... { }; objects_created++; objects_alive++; class Y : counter<Y> } { // ... virtual ~counter() }; { --objects_alive; } static int objects_created; static int objects_alive; }; template <typename T> int counter<T>::objects_created( 0 ); template <typename T> int counter<T>::objects_alive( 0 ); Vincent Agnus 14/50
  • Meta Programmation C++ Template  Curiously Recurring Template Pattern -- Exemple 2 // A class template to express an equality comparison interface. template<typename T> class equal_comparable { friend bool operator==(T const &a, T const &b) { return a.equal_to(b); } friend bool operator!=(T const &a, T const &b) { return !a.equal_to(b); } }; class value_type // Class value_type wants to have == and !=, so it derives from // equal_comparable with itself as argument (which is the CRTP). : private equal_comparable<value_type> { public: bool equal_to(value_type const& rhs) const; // to be defined }; Vincent Agnus 15/50
  • MetaProgrammation C++  Avantages – Inconvénients :  Générique  Temps compilation – Performance lors runtime  Maintenance  Portabilité • Différent compilateurs  Lisibilité : • syntaxe • message d'erreurs  Bibliothèque C++ : boost meta programming Language http://www.boost.org/doc/libs/release/libs/mpl/ Vincent Agnus 16/50
  • Type List & Dispatcher Vincent Agnus 17/50
  • Type List & Dispatcher  Objectif : Automatisation écriture de code pour la gestion de plusieurs types/classes  Exemples  problématique IRCAD  Principe de la solution mise en place  Détail de l'implémentation  Discussion Vincent Agnus 18/50
  • Type List & Dispatcher Motivation  class Shape {...}; class Point : public Shape {...}; Exemple une Fabrique class Ball : public Shape {...}; template<T> T *create() { return new T; } class TrivialShapeFactory { static Shape *build(std::string &key) { if ( key == "Point" ) { return create<Point>(); } else if ( key == "Ball" ) { return create<Ball>(); } } }; Vincent Agnus 19/50
  • Type List & Dispatcher Motivation  Plus de degrés de liberté class Shape {...}; class Point : public Shape {...}; class Ball : public Shape {...}; class Color {...}; class Red : public Color {...}; class Green : public Color {...}; class Blue : public Color {...}; template< class COLOR, class SHAPE > class ColoredShape : public SHAPE { // .... COLOR m_color; }; template< COLOR, SHAPE> Shape *createColoredShape() { return new ColoredShape< COLOR , SHAPE >; } Vincent Agnus 20/50
  • Type List & Dispatcher Motivation  La nouvelle fabrique à 2 degrés de liberté class ColoredShapeFactory { static Shape *build(std::string &color, std::string &shape) { if ( shape == "Point" ) { if ( color == "Red" ) { return createColoredShape<Red, Point>();} if ( color == "Green") { return createColoredShape<Green, Point>();} if ( color == "Blue" ) { return createColoredShape<Blue, Point>();} } else if ( shape == "Ball" ) { if ( color == "Red" ) { return createColoredShape<Red, Ball>();} // and so on ... } ... } };  Ajout d'une nouvelle classe -> risque d'erreurs  Typelist --> automatisation Vincent Agnus 21/50
  • Type List & Dispatcher Motivation  Motivation « IRCAD »  Utilisation de la librairie template ITK  template <typename PIXELTYPE, int DIM> itk::Image<PIXELTYPE,DIM>  template <typename TImageIn, typename TImageOut> itk::ImageFilter<TImageIn,TImageOut>  Nous utilisons des types images non templates (conversion <-> ITK )  void *m_buffer;  PixelType m_pixelType;  Il faut gérer les entrées/sorties des filtres avec des images de différents types Vincent Agnus 22/50
  • Type List & Dispatcher Mise en Oeuvre  Automatisation l'écriture du code  MetaProgrammation C++ :  Typelist : définir la liste des types à traiter  Le Dispatcher qui va parcourrir cette liste  Mapping entre Type de la typelist et Type requis lors du runtime  Functor (traitement)  Gestion des type list n-dimensionnelles  Cas d'utilisation : Dispatcher sur Fabriques Vincent Agnus 23/50
  • Type List & Dispatcher définition d'une type list  Type List = « Un container qui contient des types »  La boost MPL fournit plusieurs type de typelist #include<vector> #include<boost/mpl/vector.hpp> #include<boost/mpl/at.hpp> void f() { std::vector<int> classicContainer(10); int i = classicContainer.at(1); typedef boost::mpl::vector< char , std::string, int > TypeList; typedef boost::mpl::at_c< TypeList, 1 >::type StringType; StringType v = ''toto''; // OK ! } Vincent Agnus 24/50
  • Type List & Dispatcher Cas d'utilisation  Dispatcher & Fabrique a 1 degré de liberté #include <boost/mpl/vector.hpp> // used to define type list #include <Dispatcher.hpp> // define our dispatcher struct ShapeFactory { static Shape *build(std::string key) {/ // type list of supported types typedef boost::mpl::vector<Point,Ball> GeneratedShapeTypeList; Shape *shape=NULL; Dispatcher< GeneratedShapeTypeList, ShapeGenerator >::invoke(key,shape); return shape; } }; Vincent Agnus 25/50
  • Type List & Dispatcher Cas d'utilisation  Dispatcher & Fabrique a 1 degré de liberté #include <boost/mpl/vector.hpp> // used to define type list #include <Dispatcher.hpp> // define our dispatcher struct ShapeGenerator { template<class T> void operator()(Shape * &t) // we use a reference on a pointer to modify it { t=new T; } }; // Correspondance valeur clef <--> type ( fonction IsMapping ) // exemple chaine ''Point'' avec le type Point struct ShapeFactory { static Shape *build(std::string key) {/ // type list of supported types typedef boost::mpl::vector<Point,Ball> GeneratedShapeTypeList; Shape *shape=NULL; Dispatcher< GeneratedShapeTypeList, ShapeGenerator >::invoke(key,shape); return shape; } }; Vincent Agnus 26/50
  • Type List & Dispatcher Cas d'utilisation  Correspondance valeur clef <--> Type #include <TypeMapping.hpp> // used to define binding between key value and concrete type // define template isMapping function //template<typename TYPE,KEYTYPE> //bool isMapping<TYPE>(const KEYTYPE &key) //{ // // mandatory template specialization requested // // missing binding declaration involve compilation fail //} template<> bool isMapping<Point>(const std::string &key) { return key == "Point"; } template<> bool isMapping<Ball>(const std::string &key) { return key == "Ball"; } Vincent Agnus 27/50
  • Type List & Dispatcher Cas d'utilisation  Code Généré Compilation de Dispatcher< GeneratedShapeTypeList, ShapeGenerator >::invoke(key,shape);  Ps e u d o Co d e Gé n é ré { // generated at compile time if ( isMapping< Point , std::string >(key) ) { ShapeGenerator shapeGenerator; shapeGenerator.operator<Point>( shape ); } else if ( isMapping< Ball , std::string >(key) ) { ShapeGenerator shapeGenerator; shapeGenerator.operator<Ball>( shape ); } ... // same for each type stored in GeneratedShapeTypeList } Vincent Agnus 28/50
  • Type List & Dispatcher Cas d'utilisation  API du Dispatcher  Généricité vis à vis  Nature clef  Functor  Type du container de la TypeList // file Dispatcher.hpp template<class MANAGEDTYPELIST, class FUNCTOR> class Dispatcher { static void invoke(); template<class KEYTYPE> static invoke(const KEYTYPE &key); template<class KEYTYPE,class PARAMETER> static invoke(const KEYTYPE &key, PARAMETER &param); }; Vincent Agnus 29/50
  • Type List & Dispatcher Cas d'utilisation  Dispatcher & Fabrique a 2 degrés de liberté #include <Combinatory.hpp> // contain our meta-function cartesianProduct // isMapping specialized for Colors // isMapping for Combinaisont Type auto managed // functor ColoredShapeGenerator; struct ColoredShapeFactory { static Shape *build(std::string shape, std::string color) { //define two type lists for shape and color typedef boost::mpl::vector< Point, Ball >::type ManagedShape; typedef boost::mpl::vector< Red, Green, Blue >::type ManagedColor; // create the 2-dimensional typelist typedef boost::mpl::vector< ManagedShape, ManagedColor >::type MultiDimList; // generate mono-dimensional typelist with element of size 2 (shape,color) typedef boost::mpl::apply< CartesianProduct, MultiDimList>::type CombinaisonList; Shape *coloredShape=NULL; // generate the multi-key std::list< std::string > key; key.push_back(shape);key.push_back(color); Dispatcher< CombinaisonList , ColoredShapeGenerator >::invoke(key,coloredShape); return coloredShape; } }; Vincent Agnus 30/50
  • Type List & Dispatcher Cas d'utilisation  Dispatcher & Fabrique a 2 degrés de liberté  Appel du Functor ColoredShapeGenerator Dispatcher< CombinaisonList , ColoredShapeGenerator >::invoke(key,coloredShape); struct ColoredShapeGenerator { template<class TYPESEQUENCE> // paire (SHAPE,COLOR) void operator()(Shape * &t) { // insure is a TSEQUENCE BOOST_STATIC_ASSERT ( boost::mpl::is_sequence<TYPESEQUENCE>::value ); // retreive each type in 2 sized element TYPESEQUENCE typedef typename boost::mpl::at_c<TYPESEQUENCE,0>::type ChoosenShape; typedef typename boost::mpl::at_c<TYPESEQUENCE,1>::type ChoosenColor; t=new ColoredShape< ChoosenShape, ChoosenColor> ; } }; Vincent Agnus 31/50
  • Type List & Dispatcher Cas d'utilisation  Fabrique a 2 degrés de liberté  Mix des 2 types list : CombinaisonList struct ColoredShapeFactory { static Shape *build(std::string shape, std::string color) { //define two type list for shape and color typedef boost::mpl::vector< Point, Ball >::type ManagedShape; typedef boost::mpl::vector< Red, Green, Blue >::type ManagedColor; // create the 2-dimensional typelist typedef boost::mpl::vector< ManagedShape, ManagedColor >::type MultiDimList; // generate mono-dimensional typelist with element of size 2 (shape,color) typedef boost::mpl::apply< CartesianProduct, MultiDimList>::type CombinaisonList; Shape *coloredShape=NULL; // generate the multi-key std::list< std::string > key; key.push_back(shape);key.push_back(color); Dispatcher< CombinaisonList , ColoredShapeGenerator >::invoke(key,coloredShape); return coloredShape; } }; Vincent Agnus 32/50
  • Type List & Dispatcher Cas d'utilisation  Implémentation utilisant la boost::mpl  Fonction Produit Cartésien : génère les combinaisons (ordonnées) de plusieurs ensembles  Produit Cartésien de n ensembles de taille si donne un ensemble de s1⋯sn n-uplets  Exemple :   t 1,1 t 3,1 t 1,3 t  TL1= t 1,2 , TL2= 2,1 , TL3= t 3,2 t 2,2 t 3,3   t 1,1 , t 2,1 , t 3,1 , t 1,1 , t 2,1 , t 3,2  , t 1,1 ,t 2,1 ,t 3,3  , TL1⊗TL2⊗TL3 = t 1,1 , t 2,2 , t 3,1 , t 1,1 , t 2,2 , t 3,2  , t 1,1 ,t 2,2 ,t 3,3  , ⋮ ⋮ ⋮ t 1,3 , t 2,2 ,t 3,1 , t 1,3 , t 2,2 , t 3,2 , t 1,3 ,t 2,2 ,t 3,3  Vincent Agnus 33/50
  • Type List & Dispatcher Cas d'utilisation  Génération des combinaisons de typelist :  ManagedShape ~ mpl::vector<Point,Ball>  ManagedColor ~ mpl::vector<Red,Green,Bue>  MultiDimList mpl::vector< mpl::vector<Point,Ball> mpl::vector<Red,Green,Bue> >  Appel Meta Fonction Produit Cartesien typedef boost::mpl::apply< CartesianProduct, MultiDimList>::type CombinaisonList;  Génération à la compilation de : typedef boost::mpl::vector< boost::mpl::vector<Point, Red>, boost::mpl::vector<Point, Green>, boost::mpl::vector<Point, Blue>, boost::mpl::vector<Ball , Red>, boost::mpl::vector<Ball , Green, boost::mpl::vector<Ball , Blue> >::type CombinaisonList Vincent Agnus 34/50
  • Type List & Dispatcher Cas d'utilisation  Dispatcher Fabrique a 3 degrés de liberté et + : Modification mineure du code ( couleurs ) struct ColoredShapeFactory { static Shape *build(std::string shape, std::string color, std::string style) { //define two type list for shape and color typedef boost::mpl::vector< Point, Ball >::type ManagedShape; typedef boost::mpl::vector< Red, Green, Blue >::type ManagedColor; typedef boost::mpl::vector< Plain, WireFrame, Hidden >::type ManagedStyle; // create the 2-dimensional typelist typedef boost::mpl::vector< ManagedShape, ManagedColor , ManagedStyle>::type MultiDimList; // generate mono-dimensional typelist with element of size 3 (shape,color,style) typedef boost::mpl::apply< CartesianProduct, MultiDimList>::type CombinaisonList; Shape *newShape=NULL; // generate the multi-key std::list< std::string > key; key.push_back(shape);key.push_back(color); key.push_back(style); Dispatcher< CombinaisonList , 3DOFShapeGenerator >::invoke(key,newShape); return newShape; } }; Vincent Agnus 35/50
  • Type List & Dispatcher Détail  Détail d'implémentation  Dispatcher : méthod invoke  IsMapping n-D ( auto géré )  CartesianProduct Meta Function Vincent Agnus 36/50
  • Type List & Dispatcher Détail  Dispatcher : méthod invoke  Pour chaque type dans la typelist  Test si type et clef compatible isMapping  Si OK Appel functor template< class TYPELIST, class FUNCTOR > class Dispatcher { template< class KeyType, class Parameter > static void invoke( const KeyType &keytype, Parameter &param ); }; Vincent Agnus 37/50
  • Type List & Dispatcher Détail template< class TYPELIST, class FUNCTOR > class Dispatcher { template< class KeyType, class Parameter > static void invoke( const KeyType &keytype, Parameter &param ) { namespace mpl = boost::mpl; typedef typename mpl::pop_front<TYPELIST>::type Tail; typedef typename mpl::front<TYPELIST>::type Head; if ( isMapping<Head>(keytype) ) { // create the functor then excute it FUNCTOR f; f.template operator()<Head>(param); } else { // compile time : recursively call other element in the list typedef typename mpl::eval_if< mpl::empty<Tail>, mpl::identity< EmptyTypeListAction >, mpl::identity< Dispatcher<Tail,FUNCTOR > > >::type typex; typex::invoke(keytype,param); } } Vincent Agnus 38/50
  • Type List & Dispatcher Détail  Compilation de Dispatcher<ManagedShape,GeneratorFuncor>::invoke(key,shape) typedef mpl::vector<Point,Ball> ManagedShape; Dispatcher<ManagedShape, GenFunctor>::invoke( key, shape) { if( isMapping<Point>(key) ) { GenFunctor().operator<Point>()(shape); } else { typedef Dispatcher< mpl::vector<Ball>, GenFunctor> typex; typex::invoke(key,shape); } } Dispatcher< mpl::vector<Ball>, GenFunctor>::invoke( key, shape) { if ( isMapping<Ball>(key) ) { ... } else { // same API than Dispatcher but always throw ''Incorrect Key'' EmptyTypeListAction::invoke(key,shape); } } Vincent Agnus 39/50
  • Type List & Dispatcher Détail  Détail d'implémentation  Dispatcher : méthod invoke  IsMapping n-D ( auto géré )  CartesianProduct Meta Function Vincent Agnus 40/50
  • Type List & Dispatcher Détail  IsMapping : binding Type <-> valeur clef  Robuste vis à vis oublie spécialisation -> erreur de compilation template<class TYPE,class KEY> bool isMapping<TYPE>(const KEY &key) { BOOST_STATIC_ASSERT(sizeof(TYPE) == 0) }  Gestion automatique des clefs multiple càd isMapping< mpl::vector<...> >(keys) = isMapping< mpl::front(mpl::vector<...>) >(keys.front()) && isMapping< mpl::pop_front(mpl::vector<...>) >(keys.pop_front()); Vincent Agnus 41/50
  • Type List & Dispatcher Détail  Détail d'implémentation  Dispatcher : méthod invoke  IsMapping n-D ( auto géré )  CartesianProduct Meta Function Vincent Agnus 42/50
  • Type List & Dispatcher Détail  Produit cartésien est défini comme une meta fonction MPL : (équivalent functor C++) struct MaMetaFunction { template<class PARAM1, class PARAM2, ...> struct apply { typedef .... type; }; };  Appel boost::mpl::apply<MetaFct,P1,...>::type est un typedef sur MetaFct::apply<P1,...>::type  exemple boost::mpl::identity Vincent Agnus 43/50
  • Type List & Dispatcher Détail  Produit Cartésien :  Prop TL1  TL2  ...  TLn = TL1  ( TL1  (...  TLn ))) struct CartesianProduct { template< class MultiSet > struct apply { typedef typename boost::mpl::reverse_fold< MultiSet, boost::mpl::vector<>, boost::mpl::apply2< CartesianProduct_1_N_Recurser, boost::mpl::_2, boost::mpl::_1 > >::type type; }; };  3 meta fonctions intermédiaires  Au total 45 lignes Vincent Agnus 44/50
  • Type List & Dispatcher Discussion  Discussion  Généricité vis à vis clef  Spécificité de notre approche  Retour d'expériences Vincent Agnus 45/50
  • Type List & Dispatcher Discussion  Généricité vis à vis des clefs  Dimension des images : utilisation de namespace boost { namespace mpl { template< int N > struct int_ { ... }:  Gestion des Multi-méthodes : • Clef spéciale : struct TypeInfo { std::type_info *m_data}; • Spécialisation : template<> bool isMapping<Point>(const TypeInfo &key) { return *key.m_data == typeid(Point); } Vincent Agnus 46/50
  • Type List & Dispatcher Discussion  Spécificité de notre approche  Gestion native des types lists multidimensionnelles  Externalisation de la combinaison des type lists  Statique  Recherche clef type en O(n) Vincent Agnus 47/50
  • Type List & Dispatcher Discussion  Retour d'expériences  MPL : • Documentation web : boost mpl réduite • Debuggeage à la compilation par STATIC_ASSERT • Multi OS ( Linux, OsX, win32 ) OK • paradigme programmation fonctionnelle  MetaProgrammation C++ • Message erreur de compilation « illisible » • Généricité • Code Utilisateur : simplifié & sécurisé Vincent Agnus 48/50
  • Type List & Dispatcher Ressources  Livres :  Modern C++ Design, A. Alexandrescu. « C++ in depth series»  C++ Template Metaprogramming, D. Abrahams, A. Gurtovoy. « C++ in depth series»  C++ Templates - The Complete Guide, D. Vandevoorde et N. Josuttis. Addison-Wesley  Article :  En cours rédaction : « Multi-Dimensional C++ Type List » pour revue « Computer Languages, Systems & Structures » Ed. Elsevier  Distribution des sources ? Vincent Agnus 49/50
  • Merci pour votre attention Vincent Agnus 50/50