Update example to use type erased polymorphism technique

This commit is contained in:
McMassiveNZ
2023-06-29 22:50:21 +02:00
parent 9bcbe577a9
commit 4a17314eaa
5 changed files with 83 additions and 77 deletions

View File

@@ -26,6 +26,8 @@ add_executable(
${SOURCE_FILES} ${SOURCE_FILES}
) )
target_include_directories(${current_target} PRIVATE .)
if( ENABLE_ALL_REASONABLE_WARNINGS ) if( ENABLE_ALL_REASONABLE_WARNINGS )
MESSAGE("-- Additional Warnings Enabled") MESSAGE("-- Additional Warnings Enabled")
target_enable_warnings(${current_target}) target_enable_warnings(${current_target})

View File

@@ -12,9 +12,9 @@ auto main() -> int
.name = "Starter Window" .name = "Starter Window"
}); });
while (!window->ShouldClose()) while (!ShouldClose(window))
{ {
window->PumpMessages(); PumpMessages(window);
} }
} }

View File

@@ -1,28 +1,19 @@
#include "../window.h" #include "window.h"
namespace starter_window namespace starter_window
{ {
class NullWindowImpl final : public Window struct NullWindowImpl
{ {
public:
NullWindowImpl() = default;
~NullWindowImpl() override = default;
NullWindowImpl(NullWindowImpl&&) = delete;
NullWindowImpl& operator=(NullWindowImpl&&) = delete;
NullWindowImpl(const NullWindowImpl&) = delete;
NullWindowImpl& operator=(const NullWindowImpl&) = delete;
void PumpMessages() override {}
bool ShouldClose() override { return false; }
}; };
} // namespace starter_window void PumpMessages(NullWindowImpl&)
std::unique_ptr<starter_window::Window> swCreateWindow(starter_window::WindowCreateParams)
{ {
auto result = std::make_unique<starter_window::NullWindowImpl>();
return result;
} }
bool ShouldClose(const NullWindowImpl&)
{
return true;
}
} // namespace starter_window

View File

@@ -1,4 +1,4 @@
#include "../window.h" #include "window.h"
#ifndef NOMINMAX #ifndef NOMINMAX
#define NOMINMAX #define NOMINMAX
@@ -35,34 +35,43 @@ static LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM wParam, LPA
namespace starter_window namespace starter_window
{ {
class Win32WindowImpl final : public Window struct Win32WindowImpl final
{ {
public: HINSTANCE m_hInstance;
Win32WindowImpl(); HWND m_hWnd;
~Win32WindowImpl() override = default;
Win32WindowImpl(const Win32WindowImpl&) = delete;
Win32WindowImpl& operator=(const Win32WindowImpl&) = delete;
bool init(WindowCreateParams params);
void PumpMessages() override;
bool ShouldClose() override;
HINSTANCE hInstance;
HWND hWnd;
bool m_close; bool m_close;
}; };
Win32WindowImpl::Win32WindowImpl() void PumpMessages(Win32WindowImpl& window)
: hInstance(GetModuleHandle(NULL))
, hWnd(nullptr)
, m_close(false)
{ {
MSG message = {};
if (GetMessage(&message, NULL, 0, 0) != 0)
{
TranslateMessage(&message);
DispatchMessage(&message);
}
else
{
// GetMessage returned WM_QUIT
window.m_close = true;
}
} }
bool Win32WindowImpl::init(WindowCreateParams params) bool ShouldClose(const Win32WindowImpl& window)
{
return window.m_close;
}
} // namespace starter_window
starter_window::Window swCreateWindow(starter_window::WindowCreateParams params)
{ {
const char className[] = "Win32WindowImpl"; const char className[] = "Win32WindowImpl";
HINSTANCE hInstance = GetModuleHandle(NULL);
starter_window::Win32WindowImpl result = {
.m_hInstance = nullptr,
.m_hWnd = nullptr,
.m_close = true
};
WNDCLASSEX wc = {}; WNDCLASSEX wc = {};
@@ -75,7 +84,7 @@ bool Win32WindowImpl::init(WindowCreateParams params)
if (RegisterClassEx(&wc) == 0) if (RegisterClassEx(&wc) == 0)
{ {
MessageBox(nullptr, "Call to RegisterClass failed", "Fatal Error", MB_OK); MessageBox(nullptr, "Call to RegisterClass failed", "Fatal Error", MB_OK);
return false; return result;
} }
HWND window = CreateWindowEx( HWND window = CreateWindowEx(
@@ -92,41 +101,14 @@ bool Win32WindowImpl::init(WindowCreateParams params)
if (window == nullptr) if (window == nullptr)
{ {
MessageBox(nullptr, "Call to CreateWindow failed", "Fatal Error", MB_OK); MessageBox(nullptr, "Call to CreateWindow failed", "Fatal Error", MB_OK);
return false; return result;
} }
ShowWindow(window, SW_SHOW); ShowWindow(window, SW_SHOW);
return true;
}
void Win32WindowImpl::PumpMessages() result.m_hInstance = hInstance;
{ result.m_hWnd = window;
MSG message = {}; result.m_close = false;
if (GetMessage(&message, NULL, 0, 0) != 0)
{
TranslateMessage(&message);
DispatchMessage(&message);
}
else
{
// GetMessage returned WM_QUIT
m_close = true;
}
}
bool Win32WindowImpl::ShouldClose()
{
return m_close;
}
} // namespace starter_window
std::unique_ptr<starter_window::Window> swCreateWindow(starter_window::WindowCreateParams params)
{
auto result = std::make_unique<starter_window::Win32WindowImpl>();
if (result->init(params) == false)
{
result = nullptr;
}
return result; return result;
} }

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <optional>
namespace starter_window namespace starter_window
{ {
@@ -17,11 +18,41 @@ struct WindowCreateParams
class Window class Window
{ {
public: public:
virtual ~Window() = default; template<typename T>
virtual void PumpMessages() = 0; Window(T t)
virtual bool ShouldClose() = 0; : self{std::make_unique<model_t<T>>(std::move(t))}
{
}
~Window() = default;
Window(Window&&) = default;
Window& operator=(Window&&) = default;
Window(const Window&) = delete;
Window operator=(const Window&) = delete;
friend void PumpMessages(Window& window) { window.self->PumpMessages_(); }
friend bool ShouldClose(const Window& window) { return window.self->ShouldClose_(); }
private:
struct concept_t
{
virtual ~concept_t() = default;
virtual void PumpMessages_() = 0;
virtual bool ShouldClose_() const = 0;
};
template<typename T>
struct model_t final : concept_t
{
model_t(T&& data) : m_data(std::move(data)) {}
virtual void PumpMessages_() override{ PumpMessages(m_data); }
virtual bool ShouldClose_() const override { return ShouldClose(m_data); }
T m_data;
};
std::unique_ptr<concept_t> self;
}; };
} }
std::unique_ptr<starter_window::Window> swCreateWindow(starter_window::WindowCreateParams params); starter_window::Window swCreateWindow(starter_window::WindowCreateParams params);