У меня ваш пример не скомпилировался(ругался на template specialization), но не суть.
Переделал вот так:
#include <iostream>
#include <functional>
#include <SDL.h>
#include <type_traits>
using PGLCLEARPROC = std::add_pointer<void(GLbitfield mask)>::type;
using PGLCLEARCOLORPROC = std::add_pointer<void (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)>::type;
std::function<void (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)>_glClearColor;
std::function<void(GLbitfield mask)> _glClear;
void glClearColor ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
{
if(!_glClearColor)
_glClearColor = static_cast<PGLCLEARCOLORPROC>(SDL_GL_GetProcAddress( "glClearColor" ));
if (_glClearColor)
_glClearColor ( red, green, blue, alpha );
}
void glClear (GLbitfield mask)
{
if(!_glClear)
_glClear = static_cast<PGLCLEARPROC>(SDL_GL_GetProcAddress("glClear"));
if(_glClear)
_glClear (mask);
}
Здесь описание операторов:
www.cplusplus.com/reference/functional/function
Насколько я понимаю косяк заключается в том, что переменные _glClear это не указатели на функцию, а объект. И когда делаете так:
std::function <void (GLbitfield)> _glClear = NULL;
То через std::function::operator=() вы в него загоняете указатель на функцию располагающуюся в NULL. Таким образом инициализируете объект, пусть даже неправильным значением.
А когда вы делаете проверку
if( _glClear == NULL) {
То тут включается в работу оператор std::function::operator bool , которые проверяет что объект инициализирован.
Происходит преобразование типов по такому принципу: NULL -> 0 -> false. Поэтому проверка получается такой: if( _glClear == false) . Но объект уже инициализирован и operator bool возвращает true, поэтому переменная не инициализируется правильным значеним. Дальше происходит call target по адресу NULL - вы его инициалировали ранее и получаете UB.