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