Pimpl is short for "pointer to implementation" and offers a handy way to hide away implementations in classes. I'm implementing a Window-class, which hides platform-specific functions and structures from user of this class, and so the class interface ends up looking quite clean:
class Window{
public:
/// Constructors & destructors:
Window(void);
Window(Window const& window_);
Window(Window&& window_);
explicit Window(std::string const& title_);
explicit Window(std::string&& title_);
~Window(void);
/// Member data:
bool visible = false;
ContextGraphics graphics_context;
std::array<unsigned long, 2> position = {{0}}, size = {{800, 600}};
std::string title;
/// Member functions:
void apply_changes(void);
Window& center_position(void);
bool enabled(void) const;
void update(void);
/// Member functions (overloaded operators, assignment):
Window& operator=(Window const& window_);
Window& operator=(Window&& window_);
private:
/// Inner classes:
class Helper;
/// Member data:
std::unique_ptr<Window::Helper> _m_opHelper;
};
Behind the scenes are all those nasty WINAPI calls and such, and when I'm possibly aiming towards wider range of supported platforms, the class header does not need to change at all, only the source file. Very useful, no need for that much rewriting!
However, this object appears to be my problem (inside the class):
ContextGraphics graphics_context;
It's a Direct3D/OpenGL graphics context (user of "ContextGraphics" can determine that) and as you might have guessed, it uses pimpl-idiom as well:
class ContextGraphics{
/// Friends:
friend class Window;
public:
/// Enumerations:
enum class API : unsigned int{
API_DEFAULT,
API_DIRECT3D,
API_OPENGL
};
/// Constructors & destructors:
ContextGraphics(void);
explicit ContextGraphics(ContextGraphics::API const& api_);
explicit ContextGraphics(ContextGraphics::API&& api_);
~ContextGraphics(void);
/// Member data:
ContextGraphics::API api = ContextGraphics::API::API_DEFAULT;
unsigned int color_depth : 6; // 2 ^ 6 = 64
/// Member functions:
bool api_available(void) const noexcept;
bool enabled(void) const;
/// Member functions (overloaded operators, assignment):
ContextGraphics& operator=(ContextGraphics const& context_graphics_);
ContextGraphics& operator=(ContextGraphics&& context_graphics_);
private:
/// Constructors & destructors:
ContextGraphics(ContextGraphics const& context_graphics_);
ContextGraphics(ContextGraphics&& context_graphics_);
/// Inner classes:
class Helper;
/// Member data:
std::unique_ptr<ContextGraphics::Helper> _m_opHelper;
/// Member functions:
void create(void);
void destroy(void);
};
The problem I'm facing is the compiler:
Window.cpp|145|error: invalid use of incomplete type 'class ContextGraphics::Helper'|
ContextGraphics.hpp|43|error: forward declaration of 'class ContextGraphics::Helper'|
The compiler does not seem to find the implementation of class "ContextGraphics::Helper", which only raises the question if a class with pimpl can use an object with pimpl at all. Is this possible to do without putting all the implementations inside the Window-class source file? To me it doesn't seem to be a reasonable solution.