open62541pp 0.17.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
129template <typename T>
130constexpr bool isWrapper = IsWrapper<T>::value;
131
132} // namespace detail
133
134/* ------------------------------ Cast native type to wrapper type ------------------------------ */
135
136namespace detail {
137
138template <typename WrapperType>
139struct WrapperConversion {
140 static_assert(isWrapper<WrapperType>);
141 static_assert(std::is_standard_layout_v<WrapperType>);
142
143 using NativeType = typename WrapperType::NativeType;
144
145 // NOLINTBEGIN(bugprone-casting-through-void)
146 static constexpr WrapperType* asWrapper(NativeType* native) noexcept {
147 return static_cast<WrapperType*>(static_cast<void*>(native));
148 }
149
150 static constexpr const WrapperType* asWrapper(const NativeType* native) noexcept {
151 return static_cast<const WrapperType*>(static_cast<const void*>(native));
152 }
153
154 static constexpr WrapperType& asWrapper(NativeType& native) noexcept {
155 return *asWrapper(&native);
156 }
157
158 static constexpr const WrapperType& asWrapper(const NativeType& native) noexcept {
159 return *asWrapper(&native);
160 }
161
162 static constexpr NativeType* asNative(WrapperType* wrapper) noexcept {
163 return static_cast<NativeType*>(static_cast<void*>(wrapper));
164 }
165
166 static constexpr const NativeType* asNative(const WrapperType* wrapper) noexcept {
167 return static_cast<const NativeType*>(static_cast<const void*>(wrapper));
168 }
169
170 static constexpr NativeType& asNative(WrapperType& wrapper) noexcept {
171 return *asNative(&wrapper);
172 }
173
174 static constexpr const NativeType& asNative(const WrapperType& wrapper) noexcept {
175 return *asNative(&wrapper);
176 }
177
178 // NOLINTEND(bugprone-casting-through-void)
179};
180
181} // namespace detail
182
183/**
184 * @ingroup Wrapper
185 * @{
186 */
187
188/// Cast native object pointers to Wrapper object pointers.
189/// This is especially helpful to avoid copies in getter methods of composed types.
190/// @see https://github.com/open62541pp/open62541pp/issues/30
191/// @relates Wrapper
192template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
193constexpr WrapperType* asWrapper(NativeType* native) noexcept {
194 return detail::WrapperConversion<WrapperType>::asWrapper(native);
195}
196
197/// @copydoc asWrapper(NativeType*)
198/// @relates Wrapper
199template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
200constexpr const WrapperType* asWrapper(const NativeType* native) noexcept {
201 return detail::WrapperConversion<WrapperType>::asWrapper(native);
202}
203
204/// Cast native object references to Wrapper object references.
205/// @copydetails asWrapper(NativeType*)
206/// @relates Wrapper
207template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
208constexpr WrapperType& asWrapper(NativeType& native) noexcept {
209 return detail::WrapperConversion<WrapperType>::asWrapper(native);
210}
211
212/// @copydoc asWrapper(NativeType&)
213/// @relates Wrapper
214template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
215constexpr const WrapperType& asWrapper(const NativeType& native) noexcept {
216 return detail::WrapperConversion<WrapperType>::asWrapper(native);
217}
218
219/// Cast Wrapper object pointers to native object pointers.
220/// @copydoc detail::WrapperConversion
221/// @relates Wrapper
222template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
223constexpr NativeType* asNative(WrapperType* wrapper) noexcept {
224 return detail::WrapperConversion<WrapperType>::asNative(wrapper);
225}
226
227/// @copydoc asNative(WrapperType*)
228/// @relates Wrapper
229template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
230constexpr const NativeType* asNative(const WrapperType* wrapper) noexcept {
231 return detail::WrapperConversion<WrapperType>::asNative(wrapper);
232}
233
234/// Cast Wrapper object references to native object references.
235/// @copydetails asNative(WrapperType*)
236/// @relates Wrapper
237template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
238constexpr NativeType& asNative(WrapperType& wrapper) noexcept {
239 return detail::WrapperConversion<WrapperType>::asNative(wrapper);
240}
241
242/// @copydoc asNative(WrapperType&)
243/// @relates Wrapper
244template <typename WrapperType, typename NativeType = typename WrapperType::NativeType>
245constexpr const NativeType& asNative(const WrapperType& wrapper) noexcept {
246 return detail::WrapperConversion<WrapperType>::asNative(wrapper);
247}
248
249/**
250 * @}
251 */
252
253} // namespace opcua
Client * asWrapper(UA_Client *client) noexcept
Convert native UA_Client pointer to its wrapper instance.
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:208
constexpr NativeType * asNative(WrapperType *wrapper) noexcept
Cast Wrapper object pointers to native object pointers.
Definition wrapper.hpp:223
constexpr const WrapperType & asWrapper(const NativeType &native) noexcept
Cast native object references to Wrapper object references.
Definition wrapper.hpp:215
constexpr WrapperType * asWrapper(NativeType *native) noexcept
Cast native object pointers to Wrapper object pointers.
Definition wrapper.hpp:193
constexpr NativeType & asNative(WrapperType &wrapper) noexcept
Cast Wrapper object references to native object references.
Definition wrapper.hpp:238
constexpr const WrapperType * asWrapper(const NativeType *native) noexcept
Cast native object pointers to Wrapper object pointers.
Definition wrapper.hpp:200
constexpr const NativeType & asNative(const WrapperType &wrapper) noexcept
Cast Wrapper object references to native object references.
Definition wrapper.hpp:245
constexpr const NativeType * asNative(const WrapperType *wrapper) noexcept
Cast Wrapper object pointers to native object pointers.
Definition wrapper.hpp:230