将模板化的类存储到向量中

Storing templated class into vector

本文关键字:存储 向量      更新时间:2023-10-16

我基本上是想把模板化的类存储在一个std::向量中。我目前使用的解决方案是一个包含以下类型的匿名联合的结构:

struct SurfaceUnion
{
    enum { INT, FLOAT }Tag;
    union
    {
        GLSurface<int>*   iGLSurface;
        GLSurface<float>* fGLSurface;
    };
};
std::vector<SurfaceUnion*> vglSurfaces;

问题是,为了解析我需要的GLSurface,我必须做这样的事情:

for (unsigned int i = 0; i < vglSurfaces.size(); ++i)
    {
        switch (vglSurfaces[i]->Tag)
        {
        case SurfaceUnion::INT:
        {
            if (vglSurfaces[i]->iGLSurface->bIsActive && a_Camera.GetWorldSpace() == vglSurfaces[i]->iGLSurface->uiWorldSpace)
            {
                DrawSurface(*vglSurfaces[i]->iGLSurface, a_Camera);
            }
            break;
        }
        case SurfaceUnion::FLOAT:
        {
            if (vglSurfaces[i]->fGLSurface->bIsActive && a_Camera.GetWorldSpace() == vglSurfaces[i]->fGLSurface->uiWorldSpace)
            {
                DrawSurface(*vglSurfaces[i]->fGLSurface, a_Camera);
            }
            break;
        }
        }
    }

然后我终于可以直接与GLSurface交互了,而且不用复制粘贴代码

template <typename T, typename U>
void DrawSurface(const GLSurface<T>& ac_glSurface, const Camera<U>& a_Camera)
{
    glPushMatrix(); // Save the current matrix.
    glTranslatef(                                                                   // Move the image back to its original position
        ac_glSurface.Pos.X + (ac_glSurface.Center.X - ac_glSurface.OffsetD.W / 2),
        ac_glSurface.Pos.Y + (ac_glSurface.Center.Y - ac_glSurface.OffsetD.H / 2),
        0.0f); 
    glScalef(ac_glSurface.Scale.W, ac_glSurface.Scale.H, 0.0f);                     // Scale the image
    glRotatef(ac_glSurface.Rotation, 0.0f, 0.0f, 1.0f);                             // Rotate the image
    glTranslatef(                                                                   // Move the image to (0,0) on the screen
        -ac_glSurface.Pos.X - (ac_glSurface.Center.X - ac_glSurface.OffsetD.W / 2),
        -ac_glSurface.Pos.Y - (ac_glSurface.Center.Y - ac_glSurface.OffsetD.H / 2), 0.0f);
    DrawSurface(ac_glSurface);
    glPopMatrix(); // Reset the current matrix to the one that was saved.
}
template <typename T>
void DrawSurface(const GLSurface<T>& ac_glSurface)
{
    // Drawing the surface using glDrawArrays is here
}

我也有一个相机!每次我需要对相机或GLSurface做一些事情时,这都是太多的解析。这两种实现的结合完全消除了我最初试图创建的代码中真正的泛型。现在只能有一个int和一个float类型。要添加任何其他内容,我必须重写大部分代码,以便现在解析一个额外的类型。更不用说它是.lib的一部分,所以如果将来需要,在不重新编译.lib的情况下就无法添加它。此外,诸如之类的呼叫

template <typename T>
void DeleteSurface(GLSurface<T>* a_pglSurface)
{
    for (int i = 0; i < vglSurfaces.size(); ++i)
    {
        switch (vglSurfaces[i]->Tag)
        {
        case SurfaceUnion::INT:
        {
            if (vglSurfaces[i]->iGLSurface == a_pglSurface)
            {
                auto DeleteSurface = vglSurfaces[i]->iGLSurface;
                vglSurfaces.erase(vglSurfaces.begin() + i);
                glDeleteTextures(1, &DeleteSurface->Surface);
                delete DeleteSurface;
            }
            break;
        }
        case SurfaceUnion::FLOAT: 
        {
            // Will throw an error if uncommented
            /*if (vglSurfaces[i]->fGLSurface == a_pglSurface)
            {
                auto DeleteSurface = vglSurfaces[i]->fGLSurface;
                vglSurfaces.erase(vglSurfaces.begin() + i);
                glDeleteTextures(1, &DeleteSurface->Surface);
            }
            break;*/
        }
        }
    }
}

由于模板化函数的工作方式,这是不可能的。我需要像过去一样制作这两个函数,并在解析正确的类型后调用其中一个。

那么,有没有更好的方法来使用当前的实现呢?在中,我可以解析连接到"标记"枚举的未知数量的类型吗?还是完全有另一种实现?

我知道"boost"库,但这远不是一个轻量级的添加,而且它似乎不是我最初想要的。我需要直接修改GLSurface的值,不能只为它调用一个又一个访问者函数。我有20个访问者函数,我对当前实现不满意的原因是它在解析后失去了泛型和多余的函数调用。我基本上会有和现在一样的东西,但有一个巨大的依赖,包括文件夹

我也知道多态性,但我不认为有基类会有帮助,因为我需要查看不同类型的成员变量,而基类不允许我这样做

任何帮助都是非常感谢的,因为我已经被这个糟糕的代码卡住了很长一段时间。

您不能存储不同的类型。

可以通过多态引用(std::reference_wrapper)或(智能)指针存储动态实例,前提是类共享一个公共基。

否则,您应该使用静态多态性。例如,您可以查看boost::variant<GLSurface<float>, GLSurface<int>>

为了统一地操作这些,您最终会做一些静态和运行时多态性的混合:类型擦除。

使用类型擦除技术,您基本上将(不相关的)类型置于共享的特别接口下。