【问题标题】:Storing templated class into vector将模板类存储到向量中
【发布时间】:2015-11-05 22:10:10
【问题描述】:

我基本上是在尝试将模板类存储在单个 std::vector 中。我正在使用的当前解决方案是一个包含匿名联合类型的结构:

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::vector&lt;yourclass&lt;T&gt;&gt;有什么问题?
  • 这里也一样。通读一遍,无法弄清楚拥有两个不同实例化的意义何在。
  • 这一切都在命名空间内。即使不是,关键是将 GLSurface 和 GLSurface 保存在同一个向量中......你不能只说 std::vector> 除非 T 有据我所知,它被定义为一种类型,并且该类型是绝对的,这意味着它不能从 int 更改为 float。除非我根本不懂模板。
  • "[...] 从我一开始尝试创建的代码中完全消除了真正的泛型" - 哦,我想所有第一次喝酒的 C++ 程序员“通用代码”kool-aid 一直处于痛苦的阶段,他们意识到模板不容易跨越的边界(C API?孤立的 TU?)。随着时间的推移,您将知道如何预测这些边界并从一开始就为它们进行设计。在那之前,它会很痛。对不起。

标签: c++ templates vector boost unions


【解决方案1】:

你不能存储不同的类型。

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

否则你应该使用静态多态。例如,您可以查看boost::variant&lt;GLSurface&lt;float&gt;, GLSurface&lt;int&gt;&gt;

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

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

【讨论】:

  • 我查找了“类型擦除”。我找到的示例是这样的:cplusplus.com/articles/oz18T05o 该示例在结构中没有任何成员变量。我是否允许成员变量?我会通过“getter”功能访问它们吗?由于无法以某种方式直接检索值,类型擦除对我来说不是一个可行的解决方案。不过我对这个概念很感兴趣,想知道它的工作方式是否与我在示例中看到的不同。
  • 看起来是一个很好的例子。 std::function&lt;&gt; 也可以。 Boost Type Erase 是一个完整的库。
  • 如果可能的话,我想避免使用 boost,如果没有其他原因,除了在我在家/学校使用的每台机器上安装它会太麻烦。 std::function 看着我的头,但我可能会问我的教授。你能再看看我的评论吗?我在输入链接时不小心按了回车键,您回答得非常快!谢谢
  • 我认为它与您理解的工作方式不同,与您所看到的并没有太大区别。真的,我会敦促你重新考虑你的设计。你给了我所有的信号,你实际上会更好地使用单独的向量 动态多态性(例如继承和虚函数)。然后使用例如std::vector&lt;some_ptr&lt;Base&gt;&gt;。祝你好运
  • 可能,但是每个成员变量都被模板化为一个类型,而 GLSurface 是一个没有成员函数的结构。我的设计肯定不好,所以欢迎其他选择。我会查一下你的建议,然后问我的教授。我相信我能从你说的情况中弄清楚一些事情。谢谢。
猜你喜欢
  • 2014-10-24
  • 1970-01-01
  • 1970-01-01
  • 2019-06-24
  • 1970-01-01
  • 2021-11-22
  • 1970-01-01
  • 2022-07-25
  • 1970-01-01
相关资源
最近更新 更多