>>>>> "Akim" == Akim Demaille <akim(a)epita.fr> writes:
>>>> "Roland" == Roland Levillain <roland(a)lrde.epita.fr> writes:
>> Arg, désolé. Je me suis inspiré de la documentation d'Olena, qui
>> utilise \param pour les paramètres de templates, et \arg pour les
>> arguments de fonctions.
Akim> Alors il faut la corriger ! La doc de Doxygen montre ce pour quoi
Akim> c'est fait \arg.
Oui, je viens de la lire et j'ai vu la différence.
(Je CC la ML Olena.)
http://www.program-transformation.org/Tools/KoalaTools
The Koala-tools package is a collection of tools operating on the
Koala component definition language as developed by Philips Research.
Koala is a component definition language used by Philips consumer
electroniccs to model components (as C modules), composition (as C
compilation and linking), and variability (as CPP macros and partial
evaluation).
The Koala component model consists of a component language, which
supports definition of:
* interfaces (both required and provided)
* data types
* components
* diversity (by means of a diversity interfaces)
* component compositions
Component compositions consist of collections of components and wires
that connect provides and requires interfaces (see picture below).
[...]
Cf. déjà dit, le proto supportait l' ``héritage conditionnel'' ; depuis
cet été
j'ai seulement défini la liste des abstractions correspondant aux images
(ex : abstract::greylevel_image)
un objectif est de pouvoir définir des morpheurs génériques le plus
simplement possible. Le problème est double pour un tel morpheur :
- avoir l'héritage qui va bien (résolu par l'utilisation des propriétés)
- ne pas avoir à recoder les méthodes que le morpheur doit fournir.
un exemple : les valeurs d'une image (ref) sont vues à travers une
fonction (f) => une image morphée (ima). ima[p] renvoit donc f(ref[p]).
on doit pouvoir appeler ima.size() pour accéder aux dimensions de
l'image vue à travers f mais on n'a pas envie d'écrire cette méthode.
si ce type de morpheur est implémenté par la classe fimage<I,F> avec
I type de ref et F type de f, on doit redéfinir "op[]" et "op[] const"
mais on ne veut pas coder fimage<I,F>::size(). En effet, d'après la
description de ce morpheur, la méthode "size" n'est pas transformée
(on doit avoir "ima.size()" est équivalent à "ref.size()). Pire, on
ne connaît pas la liste des méthodes que l'on devraient écrire !
Si les données de ref sont stockées avec un buffer mémoire linéaire, on
peut appeler ref.buffer() pour récupérer son adresse de début et
"ref.buffer_size()" pour connaître sa taille (longueur). On doit donc
pouvoir faire de même avec ima. En revanche, si ref n'est pas
"linéaire", ima ne l'est pas non plus. Comment demander au programmeur
qui doit définir la classe paramétrée "fimage" (et ses méthodes) de
gérer tous ces cas ?
soluce
dans le proto, on définit des hiérarchies d'abstractions ; par exemple
abstract::image dont un bout est donné ci-dessous :
template <typename E>
struct image : public internal::get_image_impl < image<E>, E >
{
unsigned npoints() const // abstract
{
return this->exact().impl_npoints();
}
//...
};
ici npoints() est une méthode abstraite et on code la liaison à la main
(via this->exact().impl_)
ce qui change par rapport à "avant" (hier et les jours encore avant),
c'est le fait qu'on puisse récupérer des implémentations par défaut pour
les méthodes. elles arrivent via l'héritage de internal::get_image_impl
(notez le "get").
bien sûr, il faut écrire les implémentations par défaut (le "set" qui
correspond au "get") :
template <typename E>
struct set_image_impl < image<E>, E> : public virtual image_impl<E>
{
unsigned impl_npoints() const
{
return this->delegate().npoints();
}
//...
};
vous voyez qu'ici, ce n'est pas "exact()" (liaison) qui est appelé mais
"delegate()" (délégation). On ne rêve pas, une implémentation par
défaut signifie qu'on a un objet concret quelque part qui nous fournit
cet implémentation. Dans le cas d'un morpheur (ima), c'est bien sûr
l'image morphée (ref).
au bout du compte, un morpher "identité" (un morpheur qui ne change rien
à l'image ciblée) s'écrit en quelques lignes :
template <typename I> struct id_morpher;
template <typename I>
struct props < id_morpher<I> > : public props <I> {
typedef I delegated_type;
};
template <typename I>
struct id_morpher
: public abstract::from_image_morpher< I, id_morpher<I> >
{
typedef abstract::from_image_morpher< I, id_morpher<I> > super;
id_morpher(const I& ref) : super(ref) { exact_ptr = this; }
};
et pour vérifier que ça marche, on définit ref puis on appelle des
méthodes attendues naturellement :
int main()
{
image2d<int> ref(16, 64);
std::cout << ref.npoints() << std::endl;
// le morpheur qui en fout pas une :
id_morpher< image2d<int> > ima(ref);
std::cout << ima.npoints() << std::endl; // comme toute image
std::cout << ima(5, 1) << std::endl; // car ref est 2d
std::cout << ima.buffer_size() << std::endl; // car ref a un buf.lin.
}