#include <iostream>
#include <memory>
#include <vector>

using namespace std;


/////////////////////////////////////////
// opengl_helper.h
// this is some manager class that knows what should be initialized later
struct OpenGLHelper
{
	typedef std::function<void()> function_type;
	
	static void register_initializer(function_type fn);
	
	static std::vector<function_type> *initializer_list;
	
	static void run_init();
};
// helper class that will register some function at construction time
struct OpenGLHelper_initializer
{
	OpenGLHelper_initializer(OpenGLHelper::function_type fn)
	{
		OpenGLHelper::register_initializer(fn);
	}
};
/////////////////////////////////////////
//opengl_helper.cpp
// static pointer to a list
// it will be initialized by nullptr when program loads
// this is important to use raw pointer as it does not need to call any constructor
std::vector<OpenGLHelper::function_type> *OpenGLHelper::initializer_list = nullptr;

// function that puts initializer into a list. 
void OpenGLHelper::register_initializer(OpenGLHelper::function_type fn)
{
	if (!initializer_list)
		initializer_list = new std::vector<OpenGLHelper::function_type>;

	initializer_list->push_back(fn);
}

void OpenGLHelper::run_init()
{
	if (initializer_list)
	{
		for (auto fn : *initializer_list)
			fn();
	}
}

/////////////////////////////////////////
// figure.h
// here is sample class that will be registered for initialization
struct Square
{
	static int to_be_initialized;
	
	// static member that will register Square class to be initialized
	static OpenGLHelper_initializer __initializer;
};

/////////////////////////////////////////
// Square.cpp
int Square::to_be_initialized = 0;
// this is the most interesting part - register square into initializer list
OpenGLHelper_initializer Square::__initializer([](){
	Square::to_be_initialized = 15; 
	std::cout << "Called Square::init: " << to_be_initialized << std::endl; 
});

int main() 
{
	std::cout << "Before initialization : " << Square::to_be_initialized << std::endl;
	OpenGLHelper::run_init();
	std::cout << "After  initialization : " << Square::to_be_initialized << std::endl;
	return 0;
}