#include namespace utils { class dynamic_library { void *m_handle = nullptr; public: dynamic_library() = default; dynamic_library(const std::string &path); ~dynamic_library(); bool load(const std::string &path); void close(); private: void *get_impl(const std::string &name) const; public: template Type *get(const std::string &name) const { Type *result; *(void **)(&result) = get_impl(name); return result; } template bool get(Type *&function, const std::string &name) const { *(void **)(&function) = get_impl(name); return !!function; } bool loaded() const; explicit operator bool() const; }; // (assume the lib is always loaded) void* get_proc_address(const char* lib, const char* name); template struct dynamic_import { static_assert(sizeof(F) == 0, "Invalid function type"); }; template struct dynamic_import { R(*ptr)(Args...); const char* const lib; const char* const name; // Constant initialization constexpr dynamic_import(const char* lib, const char* name) : ptr(nullptr) , lib(lib) , name(name) { } // Caller R operator()(Args... args) { if (!ptr) { // TODO: atomic ptr = reinterpret_cast(get_proc_address(lib, name)); } return ptr(args...); } }; } #define DYNAMIC_IMPORT(lib, name, ...) static utils::dynamic_import<__VA_ARGS__> name(lib, #name);