开发者

Overloading -> operator with temporary object

I'm writing a wrapper for a mesh class, trying to implement a more intuitive interface. The mesh uses somewhat dumb iterators that can be incremented and compared but not dereferenced; instead you must get their associated feature handle from the mesh. Similarly feature handles are dumb, so to get a position / color / whatever from a vertex you have to call another function on the mesh:

Mesh mesh;
VertexIterator vertices = mesh.VerticesBegin();
VertexHandle vertex = mesh.VertexIteratorToHandle(vertices);
Vector3 vertexPosition = mesh.GetVertexPosition(vertex);

I would like to be able to instead do this:

MeshWrapper<Mesh> wrapper(mesh);
Vector3 vertexPosition = wrapper.VerticesBegin()->Positio开发者_如何学编程n();

To make this more convenient style possible, I have wrapper classes for the mesh, its iterators and handles:

template <class Mesh>
class SmartVertexHandle
{
public:
    SmartVertexHandle(Mesh::VertexHandle dumbVertexHandle, Mesh* parent);

    Vector3 Position();
    Vector3 Color(); 
    // etc ...
private:  
    Mesh* m_parent;

    typename Mesh::VertexHandle m_dumbVertexHandle;
}

template <class Mesh>
class SmartVertexIterator
{
public:
    SmartVertexHandle<Mesh>* operator->();
    // etc ...
private:
    Mesh* m_parent;
    typename Mesh::VertexIterator m_dumbVertexIterator;
}

The implementation of the -> operator is what's bothering me. I need to return a pointer to a SmartVertexHandle, but all I can get from the mesh is a dumb Mesh::VertexHandle. I currently deal with this problem like so:

template <class Mesh>
class SmartVertexIterator
{
public:
    SmartVertexHandle<Mesh>* operator->()
    {
        m_vertexWrapper = SmartVertexHandle<Mesh>(m_parent->VertexIteratorToHandle(m_dumbVertexIterator), m_parent);
        return &m_vertexWrapper;
    }
private:
    Mesh* m_parent;
    typename Mesh::VertexIterator m_dumbVertexIterator;

    SmartVertexHandle<Mesh> m_vertexWrapper;
}

This strikes me as pretty terrible and fraught with danger, not to mention being a waste of space. Is there any way to avoid it?

Sorry for the lengthy question and thanks :)


A custom operator-> has the particularity that it behaves as if operator-> is recursively called on the returned value. So given T some_type::operator->() const, this behaves as:

some_type()->some_member;
// moral equivalent:
some_type()::operator->()->some_member;

Usually it's not noticed because a plain pointer is returned, as you are attempting, so after the first operator-> the built-in -> is used and thus the chain is only 1-deep. This seems like you could use this behaviour for your needs however, using:

SmartVertexHandle<Mesh> SmartVertexIterator<Mesh>::operator->();

and

SmartVertexHandle<Mesh>* SmartVertexHandle<Mesh>::operator->()
{ return this; }

Then when the user does wrapper.VerticesBegin()->Position(), VerticesBegin() returns a SmartVertexIterator, the first operator-> returns a SmartVertexHandle, and the second, implicit, operator-> returns a pointer to this temporary handle, where the built-in -> calls SmartVertexHandle::Position. Presumably the smart handle is constructed and designed to know how to do parent->GetVertexPosition(parent->GetVertexHandle( ... ) ). Then when the full expression is evaluated the temporary SmartVertexHandle disappears gracefully.

Notice that I reused your names for SmartVertexHandle & SmartVertexIterator but I have no way of knowing if your classes can be (re)designed to be used like this. In an ideal world I would not necessarily design a separate SmartVertexHandle for the user; I'd probably write a SmartVertexIterator::proxy type for operator-> to return, then using the above technique.

All in all, I think your current approach of storing the handle is the eager version, where the handle is computed and stored whenever an iterator is constructed and is presumably recomputed whenever the iterator is e.g. incremented. My approach is a lazier version, building the handle only when asked for it (but not storing it and rebuilding it each time even when the iterator is identical). I don't think the first one is "pretty terrible" since I do not know how expensive it is to build handles compared to iterators, or how often the handles are dereferenced/used per iterator step. A third approach could even be lazier.

In both case I'd suggest not exposing SmartVertexHandle to the user (of course maybe you have requirements).

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜