2010-11-20 16 views
4

Je suis assez sûr que la réponse est "vous ne pouvez pas utiliser de modèles, vous devez utiliser des fonctions virtuelles (polymorphisme dynamique)", mais il semble que je devrais dupliquer beaucoup de code si je suis allé cette route. Voici la configuration:"modèles d'exécution"

J'ai actuellement deux classes, ColorImageSegmentation et GrayscaleImageSegmentation. Ils font essentiellement la même chose, mais il existe trois différences - ils fonctionnent sur différents types (ColorImage et GrayscaleImage) - un paramètre, la dimensionnalité de l'histogramme (3 vs 1) est différent - La fonction PixelDifference est différente en fonction de le type d'image

Si je crée une classe

template <TImageType> 
class ImageSegmentation 
{ 
}; 

Je serais en bonne forme. Cependant, je veux avoir cet objet en tant que membre d'une autre classe:

class MyMainClass 
{ 
ImageSegmentation MyImageSegmentation; 
}; 

Mais l'utilisateur doit déterminer le type de MyImageSegmentation (si l'utilisateur ouvre une image en niveaux de gris, je veux instancier MyImageSegmentation<GrayScaleType> De même pour un. . image couleur, MyImageSegmentation<ColorType>)

avec les classes dérivées, je pouvais stocker un pointeur, puis faire:

class MyMainClass 
{ 
ImageSegmentation* MyImageSegmentation; 
}; 

... user does something... 
MyImageSegmentation = new ColorImageSegmentation; 

mais comment pourrais-je faire quelque chose comme ça avec des modèles? Le problème est que j'ai beaucoup de:

typedef TImageType::HistogramType HistogramType; 
typedef TImageType::PixelType PixelType; 

genre de choses en cours, donc je ne sais pas comment je les convertir au modèle dynamique polymorphes sans dupliquer un tas de code.

Désolé pour la randonnée ... est-ce que quelqu'un a des suggestions pour moi?

Merci,

David

+0

Veuillez modifier la question pour formater correctement les exemples de code. – chris

+0

Le GIL de Boost (http://www.boost.org/doc/libs/1_45_0/libs/gil/doc/index.html) fait la même chose. Vous pouvez vérifier comment ils ont résolu ce problème. – liori

Répondre

5

Peut-être il y a des exigences supplémentaires que vous ne nous avez pas parlé, mais de ce que vous avez jusqu'à présent, vous pouvez passer le type à travers la classe contenant:

template<typename TImage> 
class MyMainClass 
{ 
    ImageSegmentation<TImage> MyImageSegmentation; 
}; 

Très probablement, vous aurez besoin d'une couche d'envoi dynamique, mais seulement au plus haut niveau d'abstraction:

struct IMainClass 
{ 
    virtual bool SaveToFile(std::string filename) = 0; 
    virtual bool ApplySharpenFilter(int level) = 0; 
    ... 
}; 

template<typename TImage> 
class MyMainClass : public IMainClass 
{ 
    ImageSegmentation<TImage> MyImageSegmentation; 
public: 
    virtual bool SaveToFile(std::string filename); 
    virtual bool ApplySharpenFilter(int level); 
}; 

IMainClass* pMain = new MyMainClass<GrayscaleImage>(); 
+0

+1: Crée une classe de base commune, puis en dérive avec une classe modélisée. – Puppy

+0

Quel est le point de faire même de l'IMainClass quelque chose? Il peut juste être vide, et alors la vraie classe modélisée peut en dériver. Cela permet toujours le IMainClass * pMain = new MyMainClass (); ce qui est exactement ce que je cherchais. Droite? –

+0

Il ne "tient" rien. C'est une interface abstraite indépendante de l'imagetype pour l'interface utilisateur (ou tout ce qui contrôle les images) pour garder une trace de l'image actuelle. Après tout, votre élément de menu "Affiner" (s'il s'agit d'un clone de photoshop) doit affecter le fichier actif, et doit le faire pour une myriade de types de fichiers. –

1

Vous souhaitez créer une version modélisée de vos objets, mais ces objets doivent-ils prendre différents types de paramètre en fonction du paramètre modélisé? Ce n'est pas une chose très facile à intégrer dans une bibliothèque, mais il y a plusieurs façons de s'y prendre.

Jetez un oeil à unary_function pour l'inspiration. Là, ils utilisent des traits pour transporter templated les paramètres de type sans avoir à travailler toute sorte de magie:

template <class Arg, class Result> 
    struct unary_function { 
    typedef Arg argument_type; 
    typedef Result result_type; 
    }; 

« unary_function » ne contient aucune fonctionnalité autre que la déclaration typedefs. Ces typedefs, cependant, vous permettent d'exprimer dans le code et au moment de la compilation des équivalents nommés entre les segments de code. Ils tirent parti de la façon dont les paramètres du modèle sont vérifiés.

Ce que cela signifie est que vous pouvez avoir des objets qui fonctionnent sur ce point:

template<typename T> 
struct Foo{ 
    typedef typename T::argument_type argument_type; 
    Foo(T _myFunc) : m_Func(_myFunc) 
    void myWrappedFunction(argument_type _argument){ m_Func(_argument); } 
}; 

qui contient en elle le type de valeur des arguments sans avoir à les préciser à l'avance. Donc, si vous avez pixel_type ou quelque chose de similaire pour chacun de vos objets d'image, alors simplement indiquer typename T::pixel_type fera suivre le paramètre de type dont vous avez besoin.

+0

wheaties, merci pour la réponse. Je ne vois pas comment cela permet à T d'être défini au moment de l'exécution? En fait, la bibliothèque que j'utilise déjà le fait, j'ai juste besoin de spécifier T à l'exécution pour que des choses comme T :: argument_type soient du bon type. –