2009-07-28 11 views
3

Dans mon aventure continue avec des modèles, j'ai modélisé ma classe Container non seulement sur le ItemType qu'elle contient, mais aussi sur un argument Functor qui détermine comment elle doit ordonner les éléments. Jusqu'ici tout va bien.Existe-t-il un moyen d'accéder aux parties privées d'une instanciation différente du même modèle de classe?

Un petit problème que j'ai rencontré se produit lorsque je veux copier le contenu d'un conteneur à un autre: Si les deux conteneurs ont des types de foncteurs différents, alors techniquement ils sont des classes non liées. Par conséquent, le conteneur A n'est pas autorisé à accéder au contenu non public du conteneur B. Existe-t-il un bon moyen de résoudre ce problème, autre que de rendre tout ce dont j'ai besoin pour accéder au public? Un moyen de modéliser une déclaration "d'ami", peut-être?

code exemple pour démontrer le problème suit:

#include <stdio.h> 

class FunctorA {}; 
class FunctorB {}; 

template <class ItemType, class Functor> class MyContainer 
{ 
public: 
    MyContainer() : _metaData(0) {/* empty */} 

    template<class RHSFunctor> void CopyFrom(const MyContainer<ItemType, RHSFunctor> & copyFrom) 
    { 
     _metaData = copyFrom._metaData; 
     _item  = copyFrom._item; 
    } 

private: 
    int _metaData; 
    ItemType _item; 
}; 

int main(int argc, char ** argv) 
{ 
    MyContainer<void *, FunctorA> containerA; 
    MyContainer<void *, FunctorB> containerB; 

    containerA.CopyFrom(containerB); // error, containerA::CopyFrom() can't access containerB's private data! 
    return 0; 
} 
+0

Clarifiée le titre pour indiquer que vous ne pouvez pas instancier une classe, mais vous pouvez instancier un modèle de classe. Une partie de la confusion découle du fait que les modèles de classe ne sont pas des types eux-mêmes, mais chaque instanciation est un type distinct. – MSalters

Répondre

2

Vous pouvez faire une classe de modèle de base basé sur un modèle juste à ItemType, conserver les données là-bas, ont les 2-args à part entière modèle sous-classe cette base, ET mettre le copy-from dans la classe de base car il ne dépend pas du foncteur de toute façon. I.e. .:

template <class ItemType> class MyContainerBase 
{ 
public: 
    MyContainerBase() : _metaData(0) {/* empty */} 

    void CopyFrom(const MyContainerBase<ItemType> & copyFrom) 
    { 
     _metaData = copyFrom._metaData; 
     _item  = copyFrom._item; 
    } 

protected: 
    int _metaData; 
    ItemType _item; 
}; 

template <class ItemType, class Functor> class MyContainer: 
    public MyContainerBase<ItemType> 
{ 
    // whatever you need here -- I made the data above protected 
    // just on the assumption you may need to access it here;-) 
}; 
+0

Jeremy, cette technique, mettre beaucoup de comportement dans une classe de base qui a moins d'arguments de template (parfois aucun) et ensuite ajouter des fonctionnalités spécifiques dans une sous-classe est une technique très générale et beaucoup utilisée. (Le GNU libstdC++ a de nombreux cas qui valent la peine d'être examinés.) – quark

+0

Génial, c'est exactement ce que je cherchais. Merci! –

1

Comme vous le soulignez, vous pouvez également utiliser une fonction ami:

class FunctorA {}; 
class FunctorB {}; 

template <class ItemType, class Functor> class MyContainer 
{ 
public: 
    MyContainer() : _metaData(0) {/* empty */} 

    template<class CmnItemType, class LHSFunctor, class RHSFunctor> 
    friend void Copy(const MyContainer<CmnItemType, LHSFunctor> & copyFrom 
    , MyContainer<CmnItemType, RHSFunctor> & copyTo); 

private: 
    int _metaData; 
    ItemType _item; 
}; 

template<class CmnItemType, class LHSFunctor, class RHSFunctor> 
void Copy(const MyContainer<CmnItemType, LHSFunctor> & copyFrom 
    , MyContainer<CmnItemType, RHSFunctor> & copyTo) 
{ 
    copyTo._metaData = copyFrom._metaData; 
    copyTo._item  = copyFrom._item; 
} 


int main(int argc, char ** argv) 
{ 
    MyContainer<void *, FunctorA> containerA; 
    MyContainer<void *, FunctorB> containerB; 

    Copy(containerB, containerA); 
    return 0; 
} 
+0

C'est aussi une bonne idée, merci! –