open62541pp 0.18.0
C++ wrapper of open62541
Loading...
Searching...
No Matches
wrapper.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <type_traits>
4#include <utility> // move
5
6namespace opcua {
7
8/**
9 * @defgroup Wrapper Wrapper classes
10 *
11 * All wrapper classes inherit from Wrapper.
12 * Native open62541 objects can be accessed using the Wrapper::handle() member function.
13 *
14 * Wrapper types are pointer-interconvertible to the wrapped native type and vice versa:
15 * - Use asWrapper(NativeType*) to cast native object pointers to wrapper object pointers.
16 * - Use asWrapper(NativeType&) to cast native object references to wrapper object references.
17 * - Use asNative(WrapperType*) to cast wrapper object pointers to native object pointers.
18 * - Use asNative(WrapperType&) to cast wrapper object references to native object references.
19 *
20 * According to the standard:
21 * > Two objects `a` and `b` are pointer-interconvertible if:
22 * > One is a standard-layout class object [wrapper] and the other is the first non-static data
23 * > member of that object [wrapped native type].
24 * Derived classes must fulfill the requirements of standard-layout types to be convertible.
25 * @see https://en.cppreference.com/w/cpp/language/static_cast#pointer-interconvertible
26 */
27
28/**
29 * Template base class to wrap native objects.
30 * @ingroup Wrapper
31 */
32template <typename T>
33class Wrapper {
34public:
35 static_assert(std::is_trivial_v<T>);
36
37 using NativeType = T;
38
39 constexpr Wrapper() noexcept = default;
40
41 /// Copy constructor with native object.
42 constexpr explicit Wrapper(const T& native) noexcept
43 : native_(native) {}
44
45 /// Move constructor with native object.
46 constexpr explicit Wrapper(T&& native) noexcept
47 : native_(std::move(native)) {}
48
49 /// Copy assignment with native object.
50 constexpr Wrapper& operator=(const T& native) noexcept {
51 this->native() = native;
52 return *this;
53 }
54
55 /// Move assignment with native object.
56 constexpr Wrapper& operator=(T&& native) noexcept {
57 this->native() = std::move(native);
58 return *this;
59 }
60
61 /// Implicit conversion to native object.
62 constexpr operator T&() noexcept { // NOLINT(hicpp-explicit-conversions)
63 return native_;
64 }
65
66 /// Implicit conversion to native object.
67 constexpr operator const T&() const noexcept { // NOLINT(hicpp-explicit-conversions)
68 return native_;
69 }
70
71 /// Member access to native object.
72 constexpr T* operator->() noexcept {
73 return &native_;
74 }
75
76 /// Member access to native object.
77 constexpr const T* operator->() const noexcept {
78 return &native_;
79 }
80
81 /// Return pointer to native object.
82 constexpr T* handle() noexcept {
83 return &native_;
84 }
85
86 /// Return pointer to native object.
87 constexpr const T* handle() const noexcept {
88 return &native_;
89 }
90
91 /// Swap with wrapper object.
92 constexpr void swap(Wrapper& other) noexcept {
93 std::swap(this->native(), other.native());
94 }
95
96 /// Swap with native object.
97 constexpr void swap(T& native) noexcept {
98 std::swap(this->native(), native);
99 }
100
101protected:
102 constexpr const T& native() const noexcept {
103 return native_;
104 }
105
106 constexpr T& native() noexcept {
107 return native_;
108 }
109
110private:
111 T native_{};
112};
113
114/* -------------------------------------------- Trait ------------------------------------------- */
115
116namespace detail {
117
118template <typename T>
119struct IsWrapper {
120 // https://stackoverflow.com/a/51910887
121 template <typename U>
122 static std::true_type check(const Wrapper<U>&);
123 static std::false_type check(...);
124
125 using type = decltype(check(std::declval<T&>()));
126 static constexpr bool value = type::value;
127};
128
129} // namespace detail
130
131/* ------------------------------ Cast native type to wrapper type ------------------------------ */
132
133namespace detail {
134
135template <typename WrapperType>
136struct WrapperConversion {
137 static_assert(detail::IsWrapper<WrapperType>::value);
138 static_assert(std::is_standard_layout_v<WrapperType>);
139
140 using NativeType = typename WrapperType::NativeType;
141
142 // NOLINTBEGIN(bugprone-casting-through-void)
143 static constexpr WrapperType* asWrapper(NativeType* native) noexcept {
144 return static_cast<WrapperType*>(static_cast<void*>(native));
145 }
146
147 static constexpr const WrapperType* asWrapper(const NativeType* native) noexcept {
148 return static_cast<const WrapperType*>(static_cast<const void*>(native));
149 }
150
151 static constexpr WrapperType& asWrapper(NativeType& native) noexcept {
152 return *asWrapper(&native);
153 }
154
155 static constexpr const WrapperType& asWrapper(const NativeType& native) noexcept {
156 return *asWrapper(&native);
157 }
158
159 static constexpr NativeType* asNative(WrapperType* wrapper) noexcept {
160 return static_cast<NativeType*>(static_cast<void*>(wrapper));
161 }
162
163 static constexpr const NativeType* asNative(const WrapperType* wrapper) noexcept {
164 return static_cast<const NativeType*>(static_cast<const void*>(wrapper));
165 }
166
167 static constexpr NativeType& asNative(WrapperType& wrapper) noexcept {
168 return *asNative(&wrapper);
169 }
170
171 static constexpr const NativeType& asNative(const WrapperType& wrapper) noexcept {
172 return *asNative(&wrapper);
173 }
174
175 // NOLINTEND(bugprone-casting-through-void)
176};
177
178} // namespace detail
179
180/**
181 * @ingroup Wrapper
182 * @{
183 */
184
185/// Cast native object pointers to Wrapper object pointers.
186/// This is especially helpful to avoid copies in getter methods of composed types.
187/// @see https://github.com/open62541pp/open62541pp/issues/30
188/// @relates Wrapper
189template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
190constexpr WrapperType* asWrapper(NativeType* native) noexcept {
191 return detail::WrapperConversion<WrapperType>::asWrapper(native);
192}
193
194/// @copydoc asWrapper(NativeType*)
195/// @relates Wrapper
196template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
197constexpr const WrapperType* asWrapper(const NativeType* native) noexcept {
198 return detail::WrapperConversion<WrapperType>::asWrapper(native);
199}
200
201/// Cast native object references to Wrapper object references.
202/// @copydetails asWrapper(NativeType*)
203/// @relates Wrapper
204template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
205constexpr WrapperType& asWrapper(NativeType& native) noexcept {
206 return detail::WrapperConversion<WrapperType>::asWrapper(native);
207}
208
209/// @copydoc asWrapper(NativeType&)
210/// @relates Wrapper
211template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
212constexpr const WrapperType& asWrapper(const NativeType& native) noexcept {
213 return detail::WrapperConversion<WrapperType>::asWrapper(native);
214}
215
216/// Cast Wrapper object pointers to native object pointers.
217/// @copydoc detail::WrapperConversion
218/// @relates Wrapper
219template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
220constexpr NativeType* asNative(WrapperType* wrapper) noexcept {
221 return detail::WrapperConversion<WrapperType>::asNative(wrapper);
222}
223
224/// @copydoc asNative(WrapperType*)
225/// @relates Wrapper
226template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
227constexpr const NativeType* asNative(const WrapperType* wrapper) noexcept {
228 return detail::WrapperConversion<WrapperType>::asNative(wrapper);
229}
230
231/// Cast Wrapper object references to native object references.
232/// @copydetails asNative(WrapperType*)
233/// @relates Wrapper
234template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
235constexpr NativeType& asNative(WrapperType& wrapper) noexcept {
236 return detail::WrapperConversion<WrapperType>::asNative(wrapper);
237}
238
239/// @copydoc asNative(WrapperType&)
240/// @relates Wrapper
241template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
242constexpr const NativeType& asNative(const WrapperType& wrapper) noexcept {
243 return detail::WrapperConversion<WrapperType>::asNative(wrapper);
244}
245
246/**
247 * @}
248 */
249
250} // namespace opcua
Template base class to wrap native objects.
Definition wrapper.hpp:33
constexpr Wrapper & operator=(const T &native) noexcept
Copy assignment with native object.
Definition wrapper.hpp:50
constexpr void swap(Wrapper &other) noexcept
Swap with wrapper object.
Definition wrapper.hpp:92
constexpr const T * operator->() const noexcept
Member access to native object.
Definition wrapper.hpp:77
constexpr T * operator->() noexcept
Member access to native object.
Definition wrapper.hpp:72
constexpr const T & native() const noexcept
Definition wrapper.hpp:102
constexpr const T * handle() const noexcept
Return pointer to native object.
Definition wrapper.hpp:87
constexpr T & native() noexcept
Definition wrapper.hpp:106
constexpr T * handle() noexcept
Return pointer to native object.
Definition wrapper.hpp:82
constexpr void swap(T &native) noexcept
Swap with native object.
Definition wrapper.hpp:97
constexpr Wrapper(T &&native) noexcept
Move constructor with native object.
Definition wrapper.hpp:46
constexpr Wrapper() noexcept=default
constexpr Wrapper & operator=(T &&native) noexcept
Move assignment with native object.
Definition wrapper.hpp:56
constexpr WrapperType & asWrapper(NativeType &native) noexcept
Cast native object references to Wrapper object references.
Definition wrapper.hpp:205
constexpr NativeType * asNative(WrapperType *wrapper) noexcept
Cast Wrapper object pointers to native object pointers.
Definition wrapper.hpp:220
constexpr const WrapperType & asWrapper(const NativeType &native) noexcept
Cast native object references to Wrapper object references.
Definition wrapper.hpp:212
constexpr WrapperType * asWrapper(NativeType *native) noexcept
Cast native object pointers to Wrapper object pointers.
Definition wrapper.hpp:190
constexpr NativeType & asNative(WrapperType &wrapper) noexcept
Cast Wrapper object references to native object references.
Definition wrapper.hpp:235
constexpr const WrapperType * asWrapper(const NativeType *native) noexcept
Cast native object pointers to Wrapper object pointers.
Definition wrapper.hpp:197
constexpr const NativeType & asNative(const WrapperType &wrapper) noexcept
Cast Wrapper object references to native object references.
Definition wrapper.hpp:242
constexpr const NativeType * asNative(const WrapperType *wrapper) noexcept
Cast Wrapper object pointers to native object pointers.
Definition wrapper.hpp:227