4

所以,我有以下问题一直困扰着我一段时间。

着色器绘制顶点。因为它是从文本文件加载到 GPU 中的,所以 OpenGL根本不需要输入它

struct Shader
{
    // Load that shader from filename
    Shader( string filename ... ) ;
} ;

在我的代码中输入了一组顶点

VertexArray<VertexPTC> ptcVerts ; // PTC is position, texcoord, color.

一个数组ptcVerts 只能由 a 绘制ptcShaderpcVerts尝试使用 a绘制数组ptShader是错误的(因为颜色值将被解释为 texcoords)。

所以我希望编译器标记出这种错误。就是这样:

template<typename T> struct Shader

现在着色器,虽然它从不使用,但它是T编译时输入的。编译器现在强制执行 aVertexArray<VertexPTC>由 a 绘制的限制Shader<VertexPTC>

这是好事还是坏事?着色器不需要或使用T,所以我担心我对模板的使用在某种程度上是一种滥用。

4

3 回答 3

2

这是一种误用。模板的使用不是免费的,当您模板化一个您愿意处理的类时会增加一些困难,因为在那里使用模板的优势

很久以后,当我需要一种通用的方法来处理 a 时,我遇到了麻烦Shader——我需要一种方法来禁用 last bound Shader,它是什么类型并不重要。

我必须人为地考虑派生的子类,或者只是从 Shader 类中Shader<T>删除模板参数。T

但实际上我找到了一种更好的方法来做到这一点。只需正常定义您的类:

struct Shader
{
  // complete, untemplatized definition.  If it doesn't use T
  // internally, THEN DO NOT INTRODUCE ARTIFICIAL DEPENDENCE ON T!
} ;

但后来我定义:

template <typename T> struct TShader : public Shader { } ;

所以现在,当您希望编译器强制执行类型时,请使用第二个TShader<T>定义。如果您不需要编译器强制类型,请使用功能齐全的基类Shader定义。

这为您提供了两全其美的体验。您始终可以在需要时将 aTShader<T>视为其未模板化的基类,而不会丢失功能或在不需要时编写抽象接口。

于 2013-07-07T20:48:17.753 回答
2

您在代码中表达了现实世界的约束。你在这里的例子实际上并没有表明在这里给你买任何东西,所以继续证据我想知道表达它是否是多余的,或者与实际出现的任何情况无关。但是,如果您要为不同类型的顶点数据集使用不同类型的着色器,我会说您在这里找到了完全正确的表达方式。

于 2013-04-24T19:02:13.893 回答
0

如果您希望编译器防止您做错事,一种方法是这样做:

class ShaderPTC
{
public:
   ShaderPTC( string filename, <other params> );
   void Draw( VertexArray<VertexPTC>& Vertices );
   ~ShaderPTC();
private:
   Shader m_shader;
}

class ShaderPC
{
public:
   ShaderPC( string filename, <other params> );
   void Draw( VertexArray<VertexPC>& Vertices );
   ~ShaderPC();
private:
   Shader m_shader;
}

您确保构造函数在内部创建适当的着色器并通过指针/引用传递此类的对象,这样您就不必关心复制包装的着色器(您可能也希望将复制构造函数/赋值设为私有) .

由于该Draw函数只接受正确类型的顶点数组并且内部着色器未公开,因此您不能传递错误的参数。

如果您必须在构造函数中编写的代码和Draw函数是通用的,您可以将其设为模板类。否则,无论如何您都必须专门化模板,从而使模板方法没有真正的好处。

虽然正确命名变量可能会防止此类问题,但正确键入变量将更难破解。

于 2013-04-24T19:28:42.950 回答