Using CRTP to split platform-specific code

I recently got this idea for separating various platform implementations (maybe Win32 / X, opengl / dx / vulkan, etc.) using CRTP (a curiously repeating template pattern): I thought of something like this:

IDisplayDevice.h

#pragma once
#include "OSConfig.h"

namespace cbn
{

    template <class TDerived> // Win32 type here
    struct IDisplayDevice
    {
        bool run_frame(void) {
            return
                static_cast<const TDerived*>(this)->run_frame();
        }
        // a lot of other methods ...       
    };
}

Win32DisplayDevice.h

#pragma once
#include "OSConfig.h"
 // make sure it only gets compiled on win32/64
#if defined(CBN_OS_WINDOWS)

namespace cbn
{
    class CWin32DisplayDevice 
      : public IDisplayDevice<CWin32DisplayDevice> {
    public:
        bool run_frame(void) {  
            call_hInstance();
            call_hWnd();
            #ifdef CBN_RENDERAPI_DX11
            call_dx11_bufferswap();
            #endif
            return some_state; 
        }
    private:
    };
}
#endif

Then I would provide another implementation in the same way in XDisplayDevice.h . Finally, I would make a common interface in DisplayDevice.h :

#include "Win32DisplayDevice.h"
#include "XDisplayDevice.h"

namespace cbn
{
    class CDisplayDevice
    {
    public:
        CBN_INLINE 
        bool run_frame(void) { return device_->run_frame(); }
    private:
#if defined(CBN_OS_WINDOWS)
        CWin32DisplayDevice device_;
#elif defined(CBN_OS_LINUX)
        CXDisplayDevice device_;
#elif // and so on
#else
        // does nothing ...
        CNillDisplayDevice device_;
#endif
    }
}

So I could call it in main.cpp , for example:

int main()
{
    CDisplayDevice my_device;
    while(my_device->run_frame())
    {
        do_some_magic();
    }
}

Do you think this will be a good way to deal with specific platform code?

PS: I avoid appetites and polymorphism due to platform limitations (android, ps4, etc.) where the pointer causes matter.

+4
2

:

struct OpenGLTraits // keep this in it own files (.h and .cpp)
{
    bool run_frame() { /* open gl specific stuff here */ }
};


struct VulkanTraits // keep this in it own files (.h and .cpp)
{
    bool run_frame() { /* vulkan specific stuff here */ }
};

template<typename T>
class DisplayDevice
{
    using graphic_traits = T;
    graphic_traits graphics; // maybe inject this in constructor?

    void do_your_operation()
    {
        if(!graphics.run_frame()) // subsystem-specific call
        { ... }
    }
};

, , API . run_frame().

( ):

:

#ifdef FLAG_SPECIFYING_OPEN_GL
using Device = DisplayDevice<OpenGLTraits>;
#elif FLAG_SPECIFYING_VULKAN
using Device = DisplayDevice<VulkanTraits>;
...
#endif

:

Device device;
device.do_your_operation();
+3

CRTP , ( ) ifdefs , , , . - , , .

:

  • /win 64
  • /win 32
  • /-Linux
  • /FreeBSD

, ifdef, , . , , . , , .

+2

Source: https://habr.com/ru/post/1652336/


All Articles