1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#ifndef CVVISUAL_UTIL_HPP
#define CVVISUAL_UTIL_HPP
// required for utilities
#include <initializer_list>
#include <memory>
#include <utility>
#include <type_traits>
// included for convinience of others:
#include <cstddef> //size_t
#include <cstdint> // [u]intXX_t
#include <algorithm> // since some people like to forget that one
namespace cvv
{
namespace util
{
/**
* @brief Creates a new Object of type T on the heap, managed by a
*std::unique_ptr.
*
* This function uses the naming-conventions of the STL instead of cvv because
*it actually
* is a backported function from C++14 that is intended to be in harmony with
*std::make_shared.
*/
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args &&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
/**
* @brief Check whether a value compares equal to any value inside a container
* of comparable types.
*/
template <typename ValueType, typename Container>
bool isAnyOf(const ValueType &value, const Container &set)
{
return std::find(set.begin(), set.end(), value) != set.end();
}
/**
* @brief Overload for intializer-lists to enable usage like this: isAnyOf(3,
* {1,2,3})
*/
template <typename ValueType, typename Comparable>
bool isAnyOf(const ValueType &value,
const std::initializer_list<Comparable> &set)
{
return std::find(set.begin(), set.end(), value) != set.end();
}
// just forward-declarations:
template <typename T> class Reference;
template <typename T> Reference<T> makeRef(T &val);
/**
* Reference-class to signal that a type is neither owned nor NULL.
*
* Note that const Reference<Foo> does not mean that the pointed to Foo is
*const. If that is what
* you want use Reference<const Foo>
*/
template <typename T> class Reference
{
public:
// there is no reasonable default-value, so:
Reference() = delete;
// these are all just the defaults but it is nice to see them explicitly
Reference(const Reference &) = default;
Reference(Reference &&) = default;
Reference &operator=(const Reference &) = default;
Reference &operator=(Reference &&) = default;
// Constructing only works from references
Reference(T &pointee) : ptr{ &pointee }
{
}
// there is no point in having a Reference to a temporary object:
Reference(T &&) = delete;
/**
* @brief Creates a Ref from a Reference to a type that inherits T.
*
* Trying to pass in any other type results in a compiler-error.
*/
template <typename Derived>
Reference(const Reference<Derived> other)
: ptr{ other.getPtr() }
{
static_assert(
std::is_base_of<T, Derived>::value,
"Reference<T> can only be constructed from Reference<U> if "
"T is either equal to U or a base-class of U");
}
/**
* @brief Get a reference to the referenced object.
*/
T &operator*() const
{
return *ptr;
}
T *operator->() const
{
return ptr;
}
/**
* @brief Get a reference to the referenced object.
*/
T &get() const
{
return *ptr;
}
/**
* @brief Get a pointer to the referenced object.
*/
T *getPtr() const
{
return ptr;
}
/**
* @brief Tries to create a Reference to a type that inherits T.
*
* If the target-type does not inherit T, a compiler-error is created.
* @throws std::bad_cast if the pointee is not of the requested type.
*/
template <typename TargetType> Reference<TargetType> castTo() const
{
static_assert(std::is_base_of<T, TargetType>::value,
"Reference<Base>::castTo<>() can only cast to "
"Reference<Derived>, "
"where Derived inherits from Base");
return makeRef(dynamic_cast<TargetType &>(*ptr));
}
/**
* @brief Compare to references for identity of the referenced object.
*
* @note identity != equality: two references to two different ints that
*both happen to have
* the value 1, will still compare unequal.
*/
bool friend operator==(const Reference &l, const Reference &r)
{
return l.ptr == r.ptr;
}
/**
* Dito.
*/
bool friend operator!=(const Reference &l, const Reference &r)
{
return l.ptr != r.ptr;
}
private:
T *ptr;
};
/**
* Create a cvv::util::Reference to an object. This is intended to be used for
* template-argument-deduction, so explicitly passing the template-argument
* should be considered
* undefined behaviour.
*/
template <typename T> Reference<T> makeRef(T &val)
{
return Reference<T>{ val };
}
}
} // namespaces
#endif