Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Patron de classe et identification du type du parametre

7 réponses
Avatar
frank
Bonjour,

J'ai une classe template Bmp qui contient une image bitmap. Cette
classe peut =EAtre instanci=E9e
avec un type ou un type RBG24_t Gray_t.

Le RGB24_t contient:
un champ de 8 bits pour le rouge
un champ de 8 bits pour le vert
un champ de 8 bits pour le bleu

Le Gray_t contient:
-un champ de 8 bits pour l'intensit=E9 de gris

Je tiens =E0 ajouter une m=E9thode pour calculer l'intensit=E9 moyenne.
mais elle doit travailler diff=E9remment
selon le param=E8tre:

Pour RGB24_t:

averageRed =3D somme de la composante rouge / nb pixels
averageGreen =3D somme des composante verte / nb pixels
averageBlue =3D somme des composante bleue / nb pixels


Pour Gray_t:

moyenne =3D somme de l'intensit=E9 de gris / nb pixels


La d=E9claration devrait ressembler a:

ComputeAverageIntensity int (composant char); / / le composant est
=ABr=BB, =ABg=BB, =ABb=BB, =ABa=BB, o=F9 a est pour le gris.

Mais comment la m=E9thode peut-elle conna=EEtre le type d'instanciation?
Elle doit verifier que le =ABa=BB est utilis=E9 uniquement quand Gray_t est
utilis=E9, aucun r, g, b lorsque Gray_t est utilis=E9, seul r, g, b
lorsque RBG24_t.

Vous pouvez proposer une autre mise en =9Cuvre de la m=E9thode, mais je
ne peux pas changer le fait que la classe est un template.

je vous remercie!

7 réponses

Avatar
Fabien LE LEZ
On Mon, 17 Jan 2011 07:28:33 -0800 (PST), frank
:

J'ai une classe template Bmp qui contient une image bitmap. Cette
classe peut être instanciée
avec un type ou un type RBG24_t Gray_t.



Tu as donc :

template <typename T> class Bmp;

et

Bmp<RBG24_t> et Bmp<Gray_t>

C'est bien ça ?


Je tiens à ajouter une méthode pour calculer l'intensité moyenne.



Es-tu absolument sûr de vouloir une fonction membre ?
S'il est possible de calculer cette intensité moyenne sans accéder aux
membres privés, tu peux en faire une fonction libre.
Ou plutôt, deux fonctions :

int ComputeAverageIntensity
(Bmp<RBG24_t> const& bitmap, char composant);
int ComputeAverageIntensity
(Bmp<Gray_t> const& bitmap, char composant);


S'il faut vraiment que cette fonction soit membre, tu peux soit
utiliser des spécialisations partielles, soit ruser un peu :

private:
static int DoComputeAverageIntensity
(Bmp<RBG24_t> const& bitmap, char composant);
static int DoComputeAverageIntensity
(Bmp<Gray_t> const& bitmap, char composant);

public:
int ComputeAverageIntensity (char composant) const
{ DoComputeAverageIntensity (*this, composant); }
Avatar
Fabien LE LEZ
J'avais écrit :

tu peux soit utiliser des spécialisations partielles,



J'ai l'esprit un peu nébuleux cette nuit. Il me semble fort que le mot
"partielles" est en trop ici.
Avatar
Michael Doubez
On 18 jan, 03:07, Fabien LE LEZ wrote:
On Mon, 17 Jan 2011 07:28:33 -0800 (PST), frank
:

> J'ai une classe template Bmp qui contient une image bitmap. Cette
>classe peut tre instanci e
> avec un type ou un type RBG24_t Gray_t.

Tu as donc :

template <typename T> class Bmp;

et

Bmp<RBG24_t> et Bmp<Gray_t>

C'est bien a ?

>Je tiens ajouter une m thode pour calculer l'intensit moyenne.

Es-tu absolument s r de vouloir une fonction membre ?
S'il est possible de calculer cette intensit moyenne sans acc der aux
membres priv s, tu peux en faire une fonction libre.
Ou plut t, deux fonctions :

int ComputeAverageIntensity
        (Bmp<RBG24_t> const& bitmap, char composant);
int ComputeAverageIntensity
        (Bmp<Gray_t> const& bitmap, char composant);

S'il faut vraiment que cette fonction soit membre, tu peux soit
utiliser des sp cialisations partielles, soit ruser un peu :

private:
  static int DoComputeAverageIntensity
        (Bmp<RBG24_t> const& bitmap, char composant);
  static int DoComputeAverageIntensity
        (Bmp<Gray_t> const& bitmap, char composant);

public:
  int ComputeAverageIntensity (char composant) const
    { DoComputeAverageIntensity (*this, composant); }



Une autre solution consiste à utiliser une classe de trait.
Quelque chose comme:

// La repésentation des pixels
struct RGB24_t
{
char red,green,blue,alpha;
};
struct Gray_t
{
char gray;
};

// les couleurs
namespace color {
// type name for each field
struct red_t{};
struct green_t{};
struct blue_t{};
struct alpha_t{};
struct gray_t{};
// ....
}

// Classe de traits pour extraite la valeur d'une couleur:
template<class T> class ColorTraits;

template<> struct ColorTraits<RGB24_t>
{
template<class TColor> static char value(RGB24_t const & rgba);
};

template<> struct ColorTraits<Gray_t>
{
template<class TColor> static char value(RGB24_t const & gray);
};

// Puis les spécialisations

template<> char
ColorTraits<RGB24_t>::value<color::red_t>(RGB24_t const & rgba)
{ return rgba.red; }

template<> char
ColorTraits<RGB24_t>::value<color::green_t>(RGB24_t const & rgba)
{ return rgba.green; }

template<> char
ColorTraits<RGB24_t>::value<color::blue_t>(RGB24_t const & rgba)
{ return rgba.blue; }

template<> char
ColorTraits<Gray_t>::value<color::gray_t>(Gray_t const & gray)
{ return gray.gray; }

Il y a peut être plus simple pour générer les traits mais là c'est à
l'huile de coude.

Ensuite tu definis ta fonction de calcul de l'intensité comme suit:

template<class TPixelColor, class TColorTrait =
ColorTraits<TPixelColor> >
class BMP
{
// ...
template<class TColor>
int ComputeAverageIntensity (TColor /* color */)
{
int intensity = 0;
for( all pixel )
{
intensity += TColorTrait::template value<TColor >(pixel);
}
return intensity;
}

};

Pour l'appel c'est du genre:
intensity = image.ComputeAverageIntensity(color::red_t());

Maintenant, comme tu passes un char, c'est un peu plus compliqué parce
que tu ne peux pas te permettre de générer toutes les fonctions en
faisant ça:

int ComputeAverageIntensity (char colorId)
{
switch(colorId)
{
case 'r': return ComputeAverageIntensity(color::red_t());
// ....
case 'g': return ComputeAverageIntensity(color::gray_t());
}
}

A la limite, tu peux utiliser une classe de trait par défaut:
template<class T> struct ColorTraits
{
template<class TColor, class TPixel>
static char value(TPixel)
{ assert( false && "unsupported color for pixel"); }
};

Ça te permettra de compiler mais tu n'aura l'erreur de mismatch qu'à
l'exécution.

Cette technique est inspiré de Boost.GIL. Si tu le peux, il sera peut
être plus rapide d'utiliser directement la bibliothèque (elle est en
HeaderOnly IIRC).

--
Michael
Avatar
frank
Fabien, tu as bien compris la situation:

template <typename T> class Bmp;


et


Bmp<RBG24_t> et Bmp<Gray_t>


C'est bien a ?



C'est preferable que la fonction soit membre parce qu'elle doit
acceder a chaque pixel. Dans le cas d'une image grise, elle doit
acceder a l'intensite du pixel et
dans le cas d'une image couleur aux trois composants red, green et
blue (dans la structure RGB24_t). Donc je retiens ta deuxieme
suggestion:

S'il faut vraiment que cette fonction soit membre, tu peux soit
utiliser des sp cialisations partielles, soit ruser un peu :

private:
static int DoComputeAverageIntensity
(Bmp<RBG24_t> const& bitmap, char composant);
static int DoComputeAverageIntensity
(Bmp<Gray_t> const& bitmap, char composant);

public:
int ComputeAverageIntensity (char composant) const
{ DoComputeAverageIntensity (*this, composant); }



Mais elle ne me contente pas completement. A l'interieur de la
fonction publique
ComputeAverageIntensity, comment savoir celle des 2 fonctions privees
appeler?
On peut y arriver en lisant le parametre composant. Mais si l'usager
s'est trompe (ex: il passe 'r' sur une image grise)
on ne peut pas l'empecher de deraper. J'aimerais que la fonction
publique sache si RGB24_t ou Gray_t a ete utilisee sans que l'usager
ait a lui dire.


frank
Avatar
pasdespam
frank wrote:

Mais elle ne me contente pas completement. A l'interieur de la
fonction publique
ComputeAverageIntensity, comment savoir celle des 2 fonctions privees
appeler?
On peut y arriver en lisant le parametre composant. Mais si l'usager
s'est trompe (ex: il passe 'r' sur une image grise)
on ne peut pas l'empecher de deraper. J'aimerais que la fonction
publique sache si RGB24_t ou Gray_t a ete utilisee sans que l'usager
ait a lui dire.



tu n'as rien a lui dire, il trouve seul la methode privée a appeller en
fonction de leurs signatures.
Avatar
Fabien LE LEZ
On Tue, 18 Jan 2011 06:11:20 -0800 (PST), frank
:

C'est preferable que la fonction soit membre parce qu'elle doit
acceder a chaque pixel.



Dans une classe "bitmap", je m'attendrais à trouver une fonction
membre publique qui permet de lire les pixels.

Cf http://www.gotw.ca/gotw/084.htm

A l'interieur de la
fonction publique
ComputeAverageIntensity, comment savoir celle des 2 fonctions privees
appeler?



Je t'ai donné l'intégralité du corps de ComputeAverageIntensity(), tu
n'as rien à changer. Laisse le compilo s'occuper des détails.
Avatar
frank
Je vous remercie les gars!