开发者

C++ - basic container question

开发者 https://www.devze.com 2023-01-10 05:05 出处:网络
How should the following cases be handled: I have some geometrical storage, which is a template from vertex type.

How should the following cases be handled:

I have some geometrical storage, which is a template from vertex type.

template <typename T> struct Geometry {

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

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

}

This works fine, unless开发者_StackOverflow社区 I want to store different types of geometries (for instance, Geometry<Vertex1> g1 and Geometry<Vertex2> g2 in one container.

Is this possible?

Or how should I implement geometry storage (where I can store and retrieve different types of geometries using one container) or maybe somehow map T type to Geometry<T> type?

Any advices?

Thank you.


As GetVertices will only return objects of type Vertex, I suggest you move to an Object Oriented design from generics.

class Vertex
{
   ....
};

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

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

typedef std::vector<Vertex*> Vertices;

struct Geometry
{
    const Vertices& GetVertices() const { .... }
    ....
};


Since a container is tied to one type of data it can contain, you could create a class GeometryBase from which all Geometry<T> are derived and then store GeometryBase pointers in your container.

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

Edit:
At some point you will have to decide which type of vertex container you want to get (my approach) or what you want to do with a vertex (Vijay Mathew's approach) and then you'll have to dynamic_cast<> in order to get access to the derived class methods.

Another suggestion:
If the types are as different as your describe in your comments, it might actually be better to treat them as different types.
For example, you could create a separate container for each Geometry<> template instance.

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

If you have functions that operate on one kind of geometry (using Vertex1::GetPos(), to use your example) or the other (Vertex2::GetUV()) then these functions are probably implemented quite differently and thus deserve to be separate functions expecting diferent types of parameters.


Heterogeneous containers (i.e., that store more than one type of object) introduce quite a few problems -- for an obvious example, when you retrieve an object, you have to do something to figure out which kind of object you're retrieving.

The containers built into C++ take the simple route: they're homogeneous -- they only store one type of object. If you want to store objects of two different types, it's up to you to wrap both of those into some third type that you store in the container (usually along with something to indicate which type a particular object really is). For example, you could do something like this:

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;

Of course, there are lots of variations (e.g., storing a pointer to a base class), but in the end it comes down to one thing: the collection itself holding one type of object, and that type somehow or other managing the two other types you need to deal with.


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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号