Question

À l'aide de PFI (curieusement récurrents de modèle de modèle), vous pouvez offrir une classe de base avec la connaissance des classes dérivées.Il n'est pas difficile de créer un tableau qui stocke une instance de chaque classe qui dérive d'une classe de base (voir l'exemple)

class Base{
    public:
        static std::vector<Base *> m_derivedInstances;
};

template <class Derived>
class CRTPBase : public Base {
    public:
        static bool m_temp;
        static bool addInstance()
        {
            m_derivedInstances.push_back(new Derived);
            return true;
        }
};
template <class Derived>
CRTPBase<Derived>::m_temp = CRTPBase<Derived>::addInstance();

Je me demandais si il était possible de créer une Typelist (voir http://www.research.ibm.com/designpatterns/pubs/ph-jun00.pdf de tous les types de classes dérivées.Le problème est que chaque fois que le compilateur voit une nouvelle classe qui dérive de Base il faudra ajouter un nouveau type à la liste, mais Typelists sont immuables (il est possible de créer une nouvelle liste avec le nouveau type est annexé, mais l'ajout d'un élément à une liste est impossible pour autant que je sais.Dans la fin, j'aimerais avoir quelque chose comme ceci:

struct DerivedClassHolder {
    typedef Loki::TL::MakeTypeList</*list all derived classes here*/>::Result DerivedTypes;
};

Le but ultime est d'être en mesure de parcourir toutes les classes qui dérivent de Base.

Était-ce utile?

La solution

Il peut être fait en utilisant un pseudo de type de la carte.Voici un exemple de code à l'aide de boost::mpl.La définition explicite de "Implem" qui peut être fait avec une macro dans chaque implem en-tête.

#include <iostream>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/mpl/empty_sequence.hpp>
#include <boost/type_traits/is_same.hpp>

using namespace boost::mpl;
using namespace boost;


// A type map. Implem #N of type Key is type (default: void)

template <typename Key, int N>
struct Implem
{
  public:
    typedef void type;
};


// Type vector building functions
// void, the default type, is used to stop the recursion

template <typename Key, int N = 1>
struct ImplemToList;

template <typename Key, typename Item, int N>
struct ImplemListItem
{
  public:
    typedef typename push_front<typename ImplemToList<Key, N + 1>::type, Item>::type type;
};

template <typename Key, int N>
struct ImplemToList
{
  public:
    typedef typename Implem<Key, N>::type item;
    typedef typename eval_if<is_same<item, void>,
                             identity<vector<> >,
                             ImplemListItem<Key, item, N> >::type type;
};


// Example code: an interface with two implems

class Interface
{
  public:
    virtual const char* name() const = 0;
};

class Implem1 : public Interface
{
  public:
    virtual const char* name() const { return "implem_1"; }
};

class Implem2 : public Interface
{
  public:
    virtual const char* name() const { return "implem_2"; }
};

template <>
struct Implem<Interface, 1>
{
  public:
    typedef Implem1 type;
};

template <>
struct Implem<Interface, 2>
{
  public:
    typedef Implem2 type;
};


void print(Interface const& i)
{
  std::cout << i.name() << std::endl;
}

int main()
{
  typedef ImplemToList<Interface>::type IList;
  for_each<IList>(&print);
}

Autres conseils

Votre typelist ne peuvent être créés par la main.Le problème que vous mentionnez, l'immuabilité, est insurmontable.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top