Pregunta

Uso de CRTP (patrón de plantilla recurrente curiosamente) Puede proporcionar una clase base con conocimiento de las clases derivadas de ella. No es tan difícil crear una matriz que almacene una instancia de cada clase que deriva de una clase base (ver ejemplo)

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();

Me preguntaba si era posible crear un tipelista (ver http : //www.research.Ibm.com/designpatterns/pubs/ph-jun00.pdf ) de todos los tipos de clases derivadas. El problema es que cada vez que el compilador ve una nueva clase que se deriva de Base, deberá agregar un nuevo tipo a la lista, pero las tipelistas son inmutables (es posible crear una nueva lista con el nuevo tipo adjunto, pero Agregar un elemento a una lista es imposible que yo sepa. Al final, me gustaría tener algo así:

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

El objetivo final es poder iterar sobre todas las clases que se derivan de Base.

¿Fue útil?

Solución

Se puede hacer, utilizando un mapa de pseudo tipo.Aquí hay algún código de ejemplo usando BOOST :: MPL.La definición explícita de "implem" se puede hacer con una macro en cada encabezado de implemento correspondiente.

#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);
}

Otros consejos

Tu tipelista solo puede ser creado a mano.El problema que mencionas, la inmutabilidad, es insuperable.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top