#ifndef CMUOH_PIMPL_HPP #define CMUOH_PIMPL_HPP #include #include // See also: https://herbsutter.com/gotw/_100/ // NOTES: // - put all private nonvirtual members (data + functions) into T impl // - when using an impl in a class, all constructors (default/copy/move) and // destructors need to be declare out of line in source file namespace cmuoh { template class pimpl; template using unique_ptr_pimpl = pimpl>; template using shared_ptr_pimpl = pimpl>; template class fast_pimpl; template class pimpl { public: template pimpl(Args&& ...); ~pimpl(); const T* operator->() const; const T& operator*() const; T* operator->(); T& operator*(); }; template class pimpl> { private: std::unique_ptr ptr; public: template constexpr pimpl(Args&& ... args) : ptr{ std::make_unique(std::forward(args)...) } { } constexpr T const & operator*() const noexcept { return *ptr.get(); } constexpr T const * operator->() const noexcept { return &**this; } constexpr T& operator*() noexcept { return *ptr.get(); } constexpr T* operator->() noexcept { return &**this; } }; template class pimpl> { private: std::shared_ptr ptr; public: template constexpr pimpl(Args&& ... args) : ptr{ std::make_shared(std::forward(args)...) } { } constexpr T const & operator*() const noexcept { return *ptr.get(); } constexpr T const * operator->() const noexcept { return &**this; } constexpr T& operator*() noexcept { return *ptr.get(); } constexpr T* operator->() noexcept { return &**this; } }; template class fast_pimpl { private: std::aligned_storage_t storage; public: template constexpr fast_pimpl(Args&&... args) noexcept { static_assert (sizeof(T) == Size, "fast_pimpl: T doesn't match expected size"); static_assert (alignof(T) <= Alignment, "fast_pimpl: T doesn't match expected alignment"); new (&**this) T { std::forward(args)... }; } constexpr fast_pimpl(fast_pimpl const& o) noexcept { new (&storage) T(*o); } constexpr fast_pimpl(fast_pimpl& o) noexcept { new (&storage) T(*o); } constexpr fast_pimpl(fast_pimpl&& o) noexcept { new (&storage) T(std::move(*o)); } ~fast_pimpl() noexcept { reinterpret_cast(&storage)->~T(); } constexpr T const & operator*() const noexcept { return *reinterpret_cast(&storage); } constexpr T const * operator->() const noexcept { return &**this; } constexpr T& operator*() noexcept { return *reinterpret_cast(&storage); } constexpr T* operator->() noexcept { return &**this; } }; } // namespace "cmuoh" #endif //CMUOH_PIMPL_HPP // /* example */ // struct impl; // int main() { // cmuoh::unique_ptr_pimpl f; //note: "impl" is forward declared // return 0; // } // struct impl { };