C++ 人工模板

C++ 人工模板,c++,templates,C++,Templates,所以,我有一个问题一直困扰着我一段时间 着色器绘制顶点组。因为它是从一个文本文件加载到GPU中的,所以OpenGL根本不需要输入它 在我的代码中,键入了一组顶点 VertexArray<VertexPTC> ptcVerts ; // PTC is position, texcoord, color. 现在,着色器(尽管它从未使用T)是在编译时键入的。编译器现在强制使用着色器绘制顶点阵列 这是好还是坏?着色器不需要或不使用T,因此我担心我使用模板在某种程度上是一种误用。您在代码中表

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

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

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

VertexArray<VertexPTC> ptcVerts ; // PTC is position, texcoord, color.
现在,着色器(尽管它从未使用
T
)是在编译时键入的。编译器现在强制使用
着色器
绘制
顶点阵列


这是好还是坏?着色器不需要或不使用
T
,因此我担心我使用模板在某种程度上是一种误用。

您在代码中表达了现实世界的约束。你在这里的例子实际上并没有表明你在这里买了什么东西,所以根据证据,我想知道表达出来是多余的,还是与实际发生的任何情况无关。但是,如果您打算为不同类型的顶点数据集使用不同类型的着色器,我想说您找到了正确的表达方法。

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

class ShaderPTC
{
public:
   ShaderPTC( string filename, <other params> );
   void Draw( VertexArray<VertexPTC>& Vertices );
   ~ShaderPTC();
private:
   Shader m_shader;
}
class ShaderPTC
{
公众:
ShaderPTC(字符串文件名,);
空心绘制(顶点阵列和顶点);
~ShaderPTC();
私人:
着色器m_着色器;
}

类ShaderPC
{
公众:
ShaderPC(字符串文件名,);
空心绘制(顶点阵列和顶点);
~ShaderPC();
私人:
着色器m_着色器;
}
确保构造函数在内部创建适当的着色器,并通过指针/引用传递此类的对象,这样就不必担心复制已包装的着色器(您可能还希望将复制构造函数/赋值设置为私有)

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

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


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

这是一种误用。模板的使用不是免费的,当你将一个你愿意处理的类模板化时,由于使用模板的好处,会增加一些困难

很久以后,当我需要一种处理
着色器
的通用方法时,我遇到了这个问题——我需要一种方法来禁用上一个绑定的
着色器
,而不管它是什么类型

我必须人工地将
Shader
派生的子类考虑进去,或者从Shader类中删除模板参数
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 { } ;
template struct TShader:public Shader{};
现在,当您希望编译器强制类型时,请使用第二个
TShader
定义。如果不需要编译器强制类型,请使用功能齐全的基类
Shader
定义


这会让你两全其美。当需要时,您始终可以将
TShader
视为其未经模板化的基类,而不会丢失功能或在不需要时编写抽象接口。

是什么使
Shader
成为
ptcShader
?还是我误解了这里发生的事?只是点名而已。一个
ptcShader
被命名,这样程序员只记得在
ptcVerts
上使用它。那么“编译器现在是如何强制限制
VertexArray
Shader
绘制的”工作的呢?我不能真正指出它为什么不好,只是因为你所说的原因,我觉得它不太合适。到处添加模板确实解决了许多问题,但根据我的经验,它也会在以后的道路上添加许多问题。我要做的是创建一个新的getter,它将始终提供相应的数组和着色器。如何实现它是你的选择,就个人而言,我不会使用模板。你使用模板作为一种粘贴在类型标签上的标签,告诉编译器在编译过程中捕获某些类型的错误。嗯,听起来很合理:类型系统就是为了这个目的而存在的。很容易尝试用错误的着色器绘制一些东西!是的。不使用类型参数并不意味着类型参数没有任何用途。这种技术引入的类型在Haskell中被调用。它们在许多语言中被广泛使用,以避免因F#中的不兼容单元(
3.0
)、坐标空间(
Point
)和轴(
Offset
)的混合而产生的常见错误。请注意,此解决方案实际上是如何手动执行模板实例化的。为什么不让编译器编写这个样板代码?@Joker\u vD,因为编写“样板”实际上可能需要更少的键入。它也没有经验较少的程序员可能会遇到的“心理成本”模板。这正是我在评论中的意思,请注意,编译器不应负责着色器的创建,将其作为pareter传递…@user1708860如果该类不处理创建着色器的问题,您可以使用
ptcShader
实例化
ShaderPC
,然后重新依赖程序员传递正确的参数。如果构造函数这样做了,您只需验证它是否达到了预期效果。否则,您必须验证实例化着色器包装器的所有代码是否使用正确的着色器进行实例化…请使用工厂,这不是构造函数的工作。
class ShaderPC
{
public:
   ShaderPC( string filename, <other params> );
   void Draw( VertexArray<VertexPC>& Vertices );
   ~ShaderPC();
private:
   Shader m_shader;
}
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 { } ;