I recently wrote this OpenGL buffer wrapper which covers the 4.5 Core specification. I feel like the typed interface could be done better. Any feedback is greatly appreciated.#ifndef MAKINA_CORE_RENDERING_BACKENDS_OPENGL_BUFFER_HPP_#define MAKINA_CORE_RENDERING_BACKENDS_OPENGL_BUFFER_HPP_#include <cstddef>#include <type_traits>#include <vector>#include <makina/core/rendering/backends/opengl/opengl.hpp>#ifdef MAKINA_OPENGL_CUDA_INTEROP  #include <cuda_gl_interop.h>  #include <cuda_runtime_api.h>#endif#include <export.hpp>namespace mak{namespace gl{template<GLenum target>class MAKINA_EXPORT buffer{public:  // 6.0 Buffer objects.  buffer()  {    glCreateBuffers(1, &id_);  }  buffer(GLuint id) : id_(id), managed_(false)  {  }  buffer(const buffer&  that) : buffer()  {    that.is_immutable()       ? set_data_immutable(that.size(), nullptr, that.storage_flags())      : set_data          (that.size(), nullptr, that.usage        ());    copy_sub_data(that, 0, 0, size());  }  buffer(      buffer&& temp) = default; ~buffer()  {    if(managed_)      glDeleteBuffers(1, &id_);  }  buffer& operator=(const buffer&  that)  {    that.is_immutable()       ? set_data_immutable(that.size(), nullptr, that.storage_flags())      : set_data          (that.size(), nullptr, that.usage        ());    copy_sub_data(that, 0, 0, size());    return *this;  }  buffer& operator=(      buffer&& temp) = default;  // 6.1 Create and bind buffer objects.  void        bind      () const  {    glBindBuffer(target, id_);  }  static void unbind    ()  {    glBindBuffer(target, 0);  }  template<typename = typename std::enable_if<target == GL_ATOMIC_COUNTER_BUFFER || target == GL_SHADER_STORAGE_BUFFER || target == GL_UNIFORM_BUFFER || target == GL_TRANSFORM_FEEDBACK_BUFFER>::type>  void        bind_range(GLuint index, GLintptr offset, GLsizeiptr size) const  {    glBindBufferRange(target, index, id_, offset, size);  }  template<typename = typename std::enable_if<target == GL_ATOMIC_COUNTER_BUFFER || target == GL_SHADER_STORAGE_BUFFER || target == GL_UNIFORM_BUFFER || target == GL_TRANSFORM_FEEDBACK_BUFFER>::type>  void        bind_base (GLuint index) const  {    glBindBufferBase(target, index, id_);  }  // 6.2 Create / modify buffer object data (bindless).  void  set_data_immutable (GLsizeiptr size, const void* data = nullptr, GLbitfield storage_flags = GL_DYNAMIC_STORAGE_BIT)  {    glNamedBufferStorage(id_, size, data, storage_flags);  }  void  set_data           (GLsizeiptr size, const void* data = nullptr, GLenum     usage         = GL_DYNAMIC_DRAW       )  {    glNamedBufferData   (id_, size, data, usage);  }  void  set_sub_data       (GLintptr offset, GLsizeiptr size, const void* data)  {    glNamedBufferSubData(id_, offset, size, data);  }   void  clear_sub_data     (GLenum internal_format, GLintptr offset, GLsizeiptr size, GLenum format, GLenum data_type, const void* data)  {    glClearNamedBufferSubData(id_, internal_format, offset, size, format, data_type, data);  }  void  clear_data         (GLenum internal_format,                                   GLenum format, GLenum data_type, const void* data)  {    glClearNamedBufferData(id_, internal_format, format, data_type, data);  }  // 6.3 Map / unmap buffer data (bindless).  void* map_range          (GLintptr offset, GLsizeiptr size, GLbitfield access_flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT) const  {    return glMapNamedBufferRange(id_, offset, size, access_flags);  }       void* map                (                                  GLenum     access       = GL_READ_WRITE) const  {    return glMapNamedBuffer(id_, access);  }  void  flush_mapped_range (GLintptr offset, GLsizeiptr size) const  {    glFlushMappedNamedBufferRange(id_, offset, size);  }  void  unmap              () const  {    glUnmapNamedBuffer(id_);  }  // 6.5 Invalidate buffer data (bindless).  void  invalidate_sub_data(GLintptr offset, GLsizeiptr size)  {    glInvalidateBufferSubData(id_, offset, size);  }  void  invalidate         ()  {    glInvalidateBufferData(id_);  }  // 6.6 Copy between buffers (bindless).  void  copy_sub_data      (const buffer& source, GLintptr source_offset, GLintptr offset, GLsizeiptr size)  {    glCopyNamedBufferSubData(source.id_, id_, source_offset, offset, size);  }  // 6.7 Buffer object queries (bindless).  bool                is_valid     () const  {    return glIsBuffer(id_);  }  std::vector<GLbyte> sub_data     (GLintptr offset, GLsizeiptr size) const  {      std::vector<GLbyte> data(size);    glGetNamedBufferSubData(id_, offset, size, static_cast<void*>(data.data()));    return data;  }  GLsizeiptr          size         () const  {    return get_parameter(GL_BUFFER_SIZE);  }  GLenum              usage        () const  {    return get_parameter(GL_BUFFER_USAGE);  }  GLenum              access       () const  {    return get_parameter(GL_BUFFER_ACCESS);  }  GLbitfield          access_flags () const  {    return get_parameter(GL_BUFFER_ACCESS_FLAGS);  }      bool                is_mapped    () const  {    return get_parameter(GL_BUFFER_MAPPED);  }  bool                is_immutable () const  {    return get_parameter(GL_BUFFER_IMMUTABLE_STORAGE);  }  GLbitfield          storage_flags() const  {    return get_parameter(GL_BUFFER_STORAGE_FLAGS);  }  GLintptr            map_offset   () const  {    return get_parameter_64(GL_BUFFER_MAP_OFFSET);  }  GLsizeiptr          map_size     () const  {    return get_parameter_64(GL_BUFFER_MAP_LENGTH);  }  void*               map_pointer  () const  {    void* pointer;    glGetNamedBufferPointerv(id_, GL_BUFFER_MAP_POINTER, &pointer);    return pointer;  }  GLuint id() const  {    return id_;  }#ifdef MAKINA_OPENGL_CUDA_INTEROP  void  cuda_register  (cudaGraphicsMapFlags flags = cudaGraphicsMapFlagsNone)  {    if (resource_ != nullptr)      cuda_unregister();    cudaGraphicsGLRegisterBuffer(&resource_, id_, flags);  }  void  cuda_unregister()  {    if (resource_ == nullptr)      return;    cudaGraphicsUnregisterResource(resource_);    resource_ = nullptr;  }  template<typename type>   type* cuda_map  ()  {    type*  buffer_ptr;    size_t buffer_size;    cudaGraphicsMapResources(1, &resource_, nullptr);    cudaGraphicsResourceGetMappedPointer(static_cast<void**>(&buffer_ptr), &buffer_size, resource_);    return buffer_ptr;  }  void  cuda_unmap()  {    cudaGraphicsUnmapResources(1, &resource_, nullptr);  }#endifprotected:  GLint   get_parameter   (GLenum parameter) const  {    GLint result;    glGetNamedBufferParameteriv(id_, parameter, &result);    return result;  }  GLint64 get_parameter_64(GLenum parameter) const  {    GLint64 result;    glGetNamedBufferParameteri64v(id_, parameter, &result);    return result;  }  GLuint id_      = 0;  bool   managed_ = true;#ifdef MAKINA_OPENGL_CUDA_INTEROP  cudaGraphicsResource* resource_ = nullptr;#endif};template<typename type, GLenum target>class MAKINA_EXPORT typed_buffer : public buffer<target>{public:  // 6.0 Buffer objects.  using buffer<target>::buffer;  using buffer<target>::operator=;  // 6.1 Create and bind buffer objects.  template<typename = typename std::enable_if<target == GL_ATOMIC_COUNTER_BUFFER || target == GL_SHADER_STORAGE_BUFFER || target == GL_UNIFORM_BUFFER || target == GL_TRANSFORM_FEEDBACK_BUFFER>::type>  void bind_range(GLuint index, GLintptr offset, GLsizeiptr size) const  {    buffer<target>::bind_range(index, sizeof(type) * offset, sizeof(type) * size);  }  // 6.2 Create / modify buffer object data (bindless).  void  set_data_immutable (GLsizeiptr size, const type* data = nullptr, GLbitfield storage_flags = GL_DYNAMIC_STORAGE_BIT)  {    buffer<target>::set_data_immutable(sizeof(type) * size, static_cast<void*>(data), storage_flags);  }  void  set_data           (GLsizeiptr size, const type* data = nullptr, GLenum     usage         = GL_DYNAMIC_DRAW       )  {    buffer<target>::set_data(sizeof(type) * size, static_cast<void*>(data), usage);  }  void  set_sub_data       (GLintptr offset, GLsizeiptr size, const type* data)  {    buffer<target>::set_sub_data(sizeof(type) * offset, sizeof(type) * size, static_cast<void*>(data));  }  void  clear_sub_data     (GLenum internal_format, GLintptr offset, GLsizeiptr size, GLenum format, GLenum data_type, const void* data)  {    buffer<target>::clear_sub_data(internal_format, sizeof(type) * offset, sizeof(type) * size, format, data_type, data);  }  // 6.3 Map / unmap buffer data (bindless).  type* map_range          (GLintptr offset, GLsizeiptr size, GLbitfield access_flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT) const  {    return static_cast<type*>(buffer<target>::map_range(sizeof(type) * offset, sizeof(type) * size, access_flags));  }  type* map                (                                  GLenum     access       = GL_READ_WRITE) const  {    return static_cast<type*>(buffer<target>::map(access));  }  void  flush_mapped_range (GLintptr offset, GLsizeiptr size) const  {    buffer<target>::flush_mapped_range(sizeof(type) * offset, sizeof(type) * size);  }  // 6.5 Invalidate buffer data (bindless).  void  invalidate_sub_data(GLintptr offset, GLsizeiptr size)  {    buffer<target>::invalidate_sub_data(sizeof(type) * offset, sizeof(type) * size);  }  // 6.6 Copy between buffers (bindless).  void  copy_sub_data      (const buffer<target>& source, GLintptr source_offset, GLintptr offset, GLsizeiptr size)  {    buffer<target>::copy_sub_data(source, sizeof(type) * source_offset, sizeof(type) * offset, sizeof(type) * size);   }  // 6.7 Buffer object queries (bindless).  std::vector<GLbyte> sub_data   (GLintptr offset, GLsizeiptr size) const  {    return buffer<target>::sub_data(sizeof(type) * offset, sizeof(type) * size);  }  GLsizeiptr          size       () const  {    return buffer<target>::size() / sizeof(type);  }  GLintptr            map_offset () const  {    return buffer<target>::map_offset() / sizeof(type);  }  GLsizeiptr          map_size   () const  {    return buffer<target>::map_size() / sizeof(type);  }  type*               map_pointer() const  {    return static_cast<type*>(buffer<target>::map_pointer());  }};template<typename type> using array_buffer              = typed_buffer<type, GL_ARRAY_BUFFER>;template<typename type> using atomic_counter_buffer     = typed_buffer<type, GL_ATOMIC_COUNTER_BUFFER>;template<typename type> using copy_read_buffer          = typed_buffer<type, GL_COPY_READ_BUFFER>;template<typename type> using copy_write_buffer         = typed_buffer<type, GL_COPY_WRITE_BUFFER>;template<typename type> using dispatch_indirect_buffer  = typed_buffer<type, GL_DISPATCH_INDIRECT_BUFFER>;template<typename type> using draw_indirect_buffer      = typed_buffer<type, GL_DRAW_INDIRECT_BUFFER>;template<typename type> using element_array_buffer      = typed_buffer<type, GL_ELEMENT_ARRAY_BUFFER>;template<typename type> using pixel_pack_buffer         = typed_buffer<type, GL_PIXEL_PACK_BUFFER>;template<typename type> using pixel_unpack_buffer       = typed_buffer<type, GL_PIXEL_UNPACK_BUFFER>;template<typename type> using query_buffer              = typed_buffer<type, GL_QUERY_BUFFER>;template<typename type> using shader_storage_buffer     = typed_buffer<type, GL_SHADER_STORAGE_BUFFER>;template<typename type> using texture_buffer            = typed_buffer<type, GL_TEXTURE_BUFFER>;template<typename type> using transform_feedback_buffer = typed_buffer<type, GL_TRANSFORM_FEEDBACK_BUFFER>;template<typename type> using uniform_buffer            = typed_buffer<type, GL_UNIFORM_BUFFER>;template<typename type> using vertex_buffer             = array_buffer        <type>;template<typename type> using index_buffer              = element_array_buffer<type>;}}#endif
OpenGL 4.5 Core Buffer wrapper
c++;c++11;opengl;wrapper