Artificial patterns

So, I have the following problem that has been going around me for some time.

Shader draws vertex groups. Since it is loaded from the an text file into the GPU, OpenGL does not require input at all.

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

Vertex group printed in my code

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

The ptcVerts array must contain < only . Trying to draw a pcVerts array using ptShader is a mistake (because color values โ€‹โ€‹will be interpreted as texcoords).

Therefore, I would like the compiler to make this type of error. Here's how:

 template<typename T> struct Shader 

now Shader, although it never uses T at all, is typed at compile time. Now the compiler sets the limit on VertexArray<VertexPTC> to Shader<VertexPTC> .

Is it good or bad ? Shader is not needed or doesnโ€™t use T , so I'm afraid that my use of templates is somehow wrong use.

+4
source share
3 answers

This is a misuse . Using templates is not free; difficulties arise when you plag a class that you are ready to handle for the benefits of using a template there.

I had problems with this much later, when I needed a general way to handle Shader - I needed a way to disable the last Shader binding, and no matter what type it was.

I had to either artificially determine the subclass from which Shader<T> is called, or simply remove the template parameter T from the Shader class.

But I really found an even better way to do this. Just define your class:

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

But then I define:

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

SO now that you want the compiler to use a type, use the definition of 2 TShader<T> . If you do not need a compiler to force type input, use the definition of a fully functional Shader base class.

It gives you the best of both worlds. You can always treat TShader<T> as an unexpanded base class when necessary, without losing functionality or having to write an abstract interface when you don't need it.

+2
source

You are expressing a real restriction in the code. Your examples here do not really show that you are buying something here, so, turning to the evidence, I wonder if it is unnecessary to express it, or is not related to any situation that really arises. But if you ever have different types of shaders for different types of vertex datasets, I would say that you typed the right way to express it here.

+2
source

If you want the compiler to stop you from doing the wrong thing, one way to do this is:

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

and

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

You will make sure that the constructors create the corresponding shader inside themselves and pass the objects of this class with pointers / links, so you do not need to worry about copying the wrapped shader (you may want to make the constructors / copy assignment private as well).

Since the Draw function accepts only the correct type of vertex array, and the internal shader is not displayed, you cannot pass incorrect parameters.

If the code you have to write in the constructors and functions of Draw is generic, you can make it a template class. Otherwise, you will have to specialize the template in any case, so that the template approach does not have real benefits.

Although properly naming your variables can prevent such problems, properly typing variables will be much harder to break.

0
source

All Articles