从零实现一个 any 类
由于 std::any 是 c++17 才有的函数,在低标准的 c++ 中想要使用这个函数很不方便,所以我参考 llvm里的代码实现了一个精简版。
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
#include <iostream>
#include <memory>
#include <typeindex>
class Any {
private:
struct HoldBase {
virtual ~HoldBase() = default;
virtual std::unique_ptr<HoldBase> Clone() const = 0;
};
template <typename T> struct Hold : public HoldBase {
Hold(const T &value)
: m_value(value) {}
Hold(T &&value)
: m_value(std::move(value)) {}
inline std::unique_ptr<HoldBase> Clone() const override {
return std::unique_ptr<HoldBase>(new Hold<T>(m_value));
}
T m_value;
private:
Hold &operator=(const Hold &other) = delete;
Hold(const Hold &other) = delete;
};
public:
Any(void)
: m_type_index(typeid(void)) {}
Any(const Any &other)
: m_holdbase(other.m_holdbase ? other.m_holdbase->Clone() : nullptr)
, m_type_index(other.m_type_index) {}
Any(Any &&other)
: m_holdbase(std::move(other.m_holdbase)), m_type_index(other.m_type_index) {}
template <typename T,class = typename std::enable_if<!std::is_same<typename std::decay<T>::type, Any>::value, T>::type>
Any(T &&value)
: m_holdbase(new Hold<typename std::decay<T>::type>(std::forward<T>(value)))
, m_type_index(typeid(typename std::decay<T>::type)) {}
Any &operator=(Any &&other) {
m_holdbase = std::move(other.m_holdbase);
m_type_index = other.m_type_index;
return *this;
}
Any &operator=(const Any &other) {
if (other.m_holdbase) {
m_holdbase = other.m_holdbase->Clone();
m_type_index = other.m_type_index;
}
return *this;
}
Any &swap(Any &other) {
std::swap(m_holdbase, other.m_holdbase);
std::swap(m_type_index, other.m_type_index);
return *this;
}
inline bool HasValue() const {
return !!m_holdbase;
}
inline void Reset() {
m_holdbase.reset();
m_type_index = typeid(void);
}
private:
template <class T> inline bool Is() const {
return m_type_index == typeid(T);
}
template <class T> inline T &AnyCast() {
if (!Is<T>()) {
if (m_type_index != typeid(void)) {
std::cout << "can not cast " << m_type_index.name() << " to "<< typeid(T).name() << std::endl;
}
throw std::bad_cast();
}
auto hold = dynamic_cast<Hold<T> *>(m_holdbase.get());
return hold->m_value;
}
private:
template <class T> friend T &AnyCast(Any &Value);
template <class T> friend T &AnyCast(Any &&Value);
template <class T> friend bool IsType(Any &value);
template <class T> friend bool IsType(Any &&value);
std::unique_ptr<HoldBase> m_holdbase;
std::type_index m_type_index;
};
template <class T> T &AnyCast(Any &value) {return value.AnyCast<T>(); }
template <class T> T &AnyCast(Any &&value) { return value.AnyCast<T>(); }
template <class T> bool IsType(Any &&value) { return value.Is<T>(); }
template <class T> bool IsType(Any &value) { return value.Is<T>(); }
int main() {
int num = 7;
Any a = num;
int ret = AnyCast<int>(a);
std::cout << ret << std::endl;
return 0;
}
本文由作者按照 CC BY 4.0 进行授权