文章

从零实现一个 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 进行授权

© xiongyi. 保留部分权利。

|

岂堪久蔽苍苍色,须放三光照九州