Я хочу написать простую оболочку RAII для объектов OpenGL (текстуры, буферы кадров и т.д.). Я заметил, что все функции glGen*
и glDelete*
имеют одну и ту же подпись, поэтому моя первая попытка была такой:
typedef void (__stdcall *GLGenFunction)(GLsizei, GLuint *);
typedef void (__stdcall *GLDelFunction)(GLsizei, const GLuint *);
template <GLGenFunction glGenFunction, GLDelFunction glDelFunction>
class GLObject
{
GLuint m_name;
public:
GLObject()
{
glGenFunction(1, &m_name);
}
~GLObject()
{
glDelFunction(1, &m_name);
}
GLuint getName() {return m_name;}
};
typedef GLObject<glGenTextures, glDeleteTextures> GLTexture;
Он отлично работает для текстур, но не работает для фреймовых буферов: glGenFramebuffers
и glDeleteFramebuffers
адреса функций не известны во время компиляции и не могут использоваться в качестве аргументов шаблона. Поэтому я сделал вторую версию:
class GLObjectBase
{
GLuint m_name;
GLDelFunction m_delFunction;
public:
GLObjectBase(GLGenFunction genFunc, GLDelFunction delFunction)
: m_delFunction(delFunction)
{
genFunc(1, &m_name);
}
GLuint getName()
{
return m_name;
}
protected:
~GLObjectBase()
{
m_delFunction(1, &m_name);
}
};
class GLFrameBuffer : public GLObjectBase
{
public:
GLFrameBuffer() : GLObjectBase(glGenFramebuffers, glDeleteFramebuffers) {}
};
Но мне это не нравится, поскольку я должен хранить указатель функции del в каждом экземпляре, который не будет меняться во время выполнения.
Как создать класс-оболочку, в котором хранится только имя объекта в каждом экземпляре, не прибегая к созданию кучки почти вставляемых в копии классов?
Я мог бы сделать что-то вроде этого:
template <int N>
class GLObject2
{
GLuint m_name;
static GLDelFunction glDelFunction;
public:
GLObject2(GLGenFunction genFunction, GLDelFunction delFunc)
{
genFunction(1, &m_name);
if ( glDelFunction == nullptr )
glDelFunction = delFunc;
ASSERT(glDelFunction == delFunc);
}
GLuint getName() {return m_name;}
protected:
~GLObject2()
{
glDelFunction(1, &m_name);
}
};
template <int N>
GLDelFunction GLObject2<N>::glDelFunction = nullptr;
class GLTexture: public GLObject2<1>
{
public:
GLTexture(): GLObject2<1>(glGenTextures, glDeleteTextures) {}
};
class GLRenderBuffer: public GLObject2<2>
{
public:
GLRenderBuffer(): GLObject2<2>(glGenRenderbuffers, glDeleteRenderbuffers) {}
};
Может ли кто-нибудь предложить более элегантное решение?