open62541pp 0.16.0
C++ wrapper of open62541
Loading...
Searching...
No Matches
typewrapper.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <type_traits>
4#include <utility> // exchange, swap
5
6#include "open62541pp/common.hpp" // TypeIndex
11
12namespace opcua {
13
14/**
15 * Template base class to wrap `UA_*` type objects.
16 *
17 * Zero cost abstraction to wrap the C API objects and delete them on destruction. The derived
18 * classes should implement specific constructors to convert from other data types.
19 *
20 * @warning No virtual constructor defined, don't implement a destructor in the derived classes.
21 * @ingroup Wrapper
22 */
23template <typename T, TypeIndex typeIndex>
24class TypeWrapper : public Wrapper<T> {
25public:
26 static_assert(typeIndex < UA_TYPES_COUNT);
27
28 constexpr TypeWrapper() = default;
29
30 /// Constructor with native object (deep copy).
31 explicit constexpr TypeWrapper(const T& native)
32 : Wrapper<T>(detail::copy(native, UA_TYPES[typeIndex])) {}
33
34 /// Constructor with native object (move rvalue).
35 constexpr TypeWrapper(T&& native) noexcept // NOLINT
36 : Wrapper<T>(std::exchange(native, {})) {}
37
39 clear();
40 };
41
42 /// Copy constructor (deep copy).
43 constexpr TypeWrapper(const TypeWrapper& other)
44 : Wrapper<T>(detail::copy(other.native(), UA_TYPES[typeIndex])) {}
45
46 /// Move constructor.
47 constexpr TypeWrapper(TypeWrapper&& other) noexcept
48 : Wrapper<T>(std::exchange(other.native(), {})) {}
49
50 /// Copy assignment (deep copy).
51 constexpr TypeWrapper& operator=(const TypeWrapper& other) {
52 if (this != &other) {
53 clear();
54 this->native() = detail::copy(other.native(), UA_TYPES[typeIndex]);
55 }
56 return *this;
57 }
58
59 /// Copy assignment with native object (deep copy).
60 constexpr TypeWrapper& operator=(const T& native) {
61 if (&this->native() != &native) {
62 clear();
63 this->native() = detail::copy(native, UA_TYPES[typeIndex]);
64 }
65 return *this;
66 }
67
68 /// Move assignment.
69 constexpr TypeWrapper& operator=(TypeWrapper&& other) noexcept {
70 if (this != &other) {
71 clear();
72 this->native() = std::exchange(other.native(), {});
73 }
74 return *this;
75 }
76
77 /// Move assignment with native object.
78 constexpr TypeWrapper& operator=(T&& native) noexcept { // NOLINT
79 if (&this->native() != &native) {
80 clear();
81 this->native() = std::exchange(native, {});
82 }
83 return *this;
84 }
85
86 /// Swap with wrapper object.
87 constexpr void swap(TypeWrapper& other) noexcept {
88 static_assert(std::is_nothrow_swappable_v<T>);
89 std::swap(this->native(), other.native());
90 }
91
92 /// Swap with native object.
93 constexpr void swap(T& native) noexcept {
94 static_assert(std::is_nothrow_swappable_v<T>);
95 std::swap(this->native(), native);
96 }
97
98 /// Get type as type index of the ::UA_TYPES array.
99 static constexpr TypeIndex getTypeIndex() {
100 return typeIndex;
101 }
102
103protected:
104 constexpr void clear() noexcept {
105 detail::clear(this->native(), UA_TYPES[typeIndex]);
106 }
107};
108
109/* -------------------------------------------- Trait ------------------------------------------- */
110
111namespace detail {
112
113template <typename T>
115 // https://stackoverflow.com/a/51910887
116 template <typename U, TypeIndex typeIndex>
117 static std::true_type check(const TypeWrapper<U, typeIndex>&);
118
119 static std::false_type check(...);
120
121 using type = decltype(check(std::declval<T&>())); // NOLINT, false positive?
122 static constexpr bool value = type::value;
123};
124
125template <typename T>
127
128} // namespace detail
129
130/* --------------------------------- TypeRegistry specialization -------------------------------- */
131
132template <typename T>
133struct TypeRegistry<T, std::enable_if_t<detail::isTypeWrapper<T>>> {
134 static const UA_DataType& getDataType() noexcept {
135 return UA_TYPES[T::getTypeIndex()];
136 }
137};
138
139} // namespace opcua
Template base class to wrap UA_* type objects.
constexpr TypeWrapper & operator=(T &&native) noexcept
Move assignment with native object.
constexpr void swap(TypeWrapper &other) noexcept
Swap with wrapper object.
constexpr void clear() noexcept
constexpr TypeWrapper(const TypeWrapper &other)
Copy constructor (deep copy).
static constexpr TypeIndex getTypeIndex()
Get type as type index of the UA_TYPES array.
constexpr TypeWrapper(const T &native)
Constructor with native object (deep copy).
constexpr TypeWrapper()=default
constexpr TypeWrapper & operator=(const T &native)
Copy assignment with native object (deep copy).
constexpr TypeWrapper(TypeWrapper &&other) noexcept
Move constructor.
constexpr void swap(T &native) noexcept
Swap with native object.
constexpr TypeWrapper(T &&native) noexcept
Constructor with native object (move rvalue).
constexpr TypeWrapper & operator=(TypeWrapper &&other) noexcept
Move assignment.
constexpr TypeWrapper & operator=(const TypeWrapper &other)
Copy assignment (deep copy).
Template base class to wrap native objects.
Definition wrapper.hpp:32
constexpr const T & native() const noexcept
Definition wrapper.hpp:75
constexpr Wrapper()=default
constexpr T copy(const T &src, const UA_DataType &type) noexcept(isPointerFree< T >)
constexpr bool isTypeWrapper
constexpr void clear(T &native, const UA_DataType &type) noexcept
uint16_t TypeIndex
Type index of the UA_TYPES array.
Definition common.hpp:21
static std::true_type check(const TypeWrapper< U, typeIndex > &)
decltype(check(std::declval< T & >())) type
static constexpr bool value
static std::false_type check(...)
const UA_DataType UA_TYPES[191]
#define UA_TYPES_COUNT