Pimpl

mrs_lib::Pimpl

template<typename Interface, typename StorageType = std::unique_ptr<Interface>>
class Pimpl

Owning pointer wrapper with move only value semantics. Usefull for implementing the pointer to implementation (PIMPL) pattern.

Contains the specified value using the StorageType. Compared to std::*_ptr, this class uses deep const semantics and is not nullable (with the exception of the moved from state in which it should not be used).

When implementing the PIMPL pattern for your own classes, the default pointer type should be correct.

This class can also be used to wrap non nullable ros interfaces (eg. rclcpp::Publisher), which are provided as std::shared_ptr. In those cases you can set StorageType to std::shared_ptr (eg. for the publisher: mrs_lib::Pimpl<rclcpp::Publisher, std::shared_ptr<rclcpp::Publisher>>). The class will keep the same semantics, but will use different storage.

Template Parameters:
  • Interface – The interface / class type that the Pimpl will hold.

  • StorageType – The type of value used to store for the implementation (defaults to std::unique_ptr<Interface>).

Public Functions

explicit Pimpl(std::nullptr_t) = delete

Deleted constructor to prevent construction from nullptr.

inline explicit Pimpl(StorageType impl)

Construct Pimpl from a pointer to the object.

Parameters:

impl – The pointer to the implementation object.

Throws:

std::logic_error – if impl is nullptr.

template<typename T, typename ...Args>
inline explicit Pimpl(std::in_place_type_t<T>, Args&&... args)

Construct the wrapped object in place.

Template Parameters:
  • T – The concrete type of the object to construct.

  • Args – Types of arguments passed to the inner object’s constructor.

Parameters:
  • - – Tag type to distinguish between overloads and select the concrete type.

  • args – Arguments to construct the inner object with.

~Pimpl() = default

Default destructor.

Pimpl(const Pimpl&) = delete

Pimpl is not copyable.

Pimpl &operator=(const Pimpl&) = delete

Pimpl is not copyable.

Pimpl(Pimpl&&) = default

Default move constructor.

Pimpl &operator=(Pimpl&&) = default

Default move assignment operator.

inline Interface &operator*() noexcept

Dereference operator for non-const access.

Returns:

Reference to the underlying implementation object.

inline const Interface &operator*() const noexcept

Dereference operator for const access.

Returns:

Reference to the underlying implementation object.

inline Interface *operator->() noexcept

Arrow operator for non-const access.

Returns:

Pointer to the underlying implementation object.

inline const Interface *operator->() const noexcept

Arrow operator for const access.

Returns:

Pointer to the underlying implementation object.

inline bool valueless_after_move() const noexcept

Checks if the object is in moved from state.

Can be used on moved from object.

Note

This function should not be needed in most cases. You should not keep moved from objects alive for long periods of time.

Example

Example of the Pimpl usage.
 1class MyClass
 2{
 3  class Impl;
 4
 5public:
 6  MyClass() : impl_(std::in_place_type_t<Impl>{}, 21)
 7  {
 8  }
 9
10  int calculate();
11
12private:
13  mrs_lib::Pimpl<Impl> impl_;
14};
15
16class MyClass::Impl
17{
18public:
19  Impl(int val) : val_(val)
20  {
21  }
22
23  int calculate()
24  {
25    return val_ * 2;
26  }
27
28private:
29  int val_;
30};
31
32int MyClass::calculate()
33{
34  return impl_->calculate();
35}