C ++ - базовый контейнерный вопрос - PullRequest
0 голосов
/ 03 августа 2010

Как должны обрабатываться следующие случаи:

У меня есть некоторая геометрическая память, которая является template от типа вершины.

template <typename T> struct Geometry {

std::vector<T>& GetVertices() { ... }

const void* RawVertices() const { ... }

}

Это работаетхорошо, если только я не хочу хранить различные типы геометрии (например, Geometry<Vertex1> g1 и Geometry<Vertex2> g2 в одном контейнере.

Возможно ли это?

или какя должен реализовать хранение геометрии (где я могу хранить и извлекать различные типы геометрий, используя один контейнер) или, может быть, каким-то образом сопоставить T тип с Geometry<T> типом?

Любые советы?

Спасибовы.

Ответы [ 4 ]

3 голосов
/ 03 августа 2010

Поскольку GetVertices будет возвращать только объекты типа Vertex, я предлагаю вам перейти к объектно-ориентированному дизайну из шаблонов.

class Vertex
{
   ....
};

class Vertex1 : public Vertex 
{
   ....
};

class Vertex2 : public Vertex 
{
   ....
};

typedef std::vector<Vertex*> Vertices;

struct Geometry
{
    const Vertices& GetVertices() const { .... }
    ....
};
2 голосов
/ 03 августа 2010

Поскольку контейнер привязан к одному типу данных, которые он может содержать, вы можете создать класс GeometryBase, из которого получены все Geometry<T>, а затем сохранить GeometryBase указатели в вашем контейнере.

struct GeometryBase
{
    // Non-template methods might go here.
    // Don't forget to declare the base class destructor virtual.
};

template <typename T> struct Geometry : public GeometryBase
{
    // Template methods go here
};

Редактировать:
В какой-то момент вам придется решить, какой тип контейнера вершин вы хотите получить (мой подход) или , что вы хотите сделать с вершиной(Подход Vijay Mathew), а затем вам нужно будет dynamic_cast <>, чтобы получить доступ к методам производного класса.

Еще одно предложение:
Если типы различныкак вы описываете в своих комментариях, на самом деле может быть лучше рассматривать их как разные типы.
Например, вы можете создать отдельный контейнер для каждого Geometry<> экземпляра шаблона.

class SomeStorageClass
{
/* ... */
private:
    std::vector< Geometry<Vertex1> > m_vertex1Geometries;
    std::vector< Geometry<Vertex2> > m_vertex2Geometries;
};

Если выесть функции, которые работают с одним типом геометрии (используя Vertex1::GetPos(), если использовать ваш пример) или с другим (Vertex2::GetUV()), тогда эти функции, вероятно, реализованы совершенно по-разному и, следовательно, заслуживают отдельной функции.ожидающие разные типы параметров.

1 голос
/ 03 августа 2010
class IGeometry
{
public:
    virtual const void* RawVertices() const = 0;
    virtual ~IGeometry() {}

    template <typename T>
    std::vector<T>& GetVertices() const 
    { 
        typedef const Geometry<T>* AppropriateDerivedClass;
        return dynamic_cast<AppropriateDerivedClass>(this)->GetVertices();
    };
};
1 голос
/ 03 августа 2010

Гетерогенные контейнеры (то есть, которые хранят более одного типа объектов) создают довольно много проблем - для очевидного примера, когда вы извлекаете объект, вы должны сделать что-то, чтобы выяснить, какой тип объекта вы при получении.

Контейнеры, встроенные в C ++, выбирают простой путь: они однородны - они хранят только один тип объекта. Если вы хотите хранить объекты двух разных типов, вам нужно обернуть их оба в какой-то третий тип, который вы храните в контейнере (обычно вместе с чем-то, чтобы указать, к какому типу относится конкретный объект). Например, вы можете сделать что-то вроде этого:

class vertex1 {};

class vertex2 {};

class vertex {
    vertex1 *v1;
    vertex2 *v2;
public:
    vertex(vertex1 *init1) : v1(init1), v2(NULL) {}
    vertex(vertex2 *init2) : v1(NULL), v2(init2) {}
};

std::vector<vertex> vertices;

Конечно, существует множество вариаций (например, хранение указателя на базовый класс), но в итоге все сводится к одному: сама коллекция содержит один тип объекта, и этот тип так или иначе управляет два других типа, с которыми вам нужно иметь дело.

...