文章

自己实现一个 any

最近的业务中需要用到 std::any,但编译器版本又太低,于是自己实现了一个(参考 llvm),用法参见std::any的用法,前面有介绍过。

代码实现

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
// c++14 才有这个头文件,所以可以自己实现一个,或者使用 new
#include "make_unique.h"

#include <iostream>
#include <memory>
#include <typeindex>

class Any
{
private:
    template<class T>
    friend T &any_cast(Any &Value);
    template<class T>
    friend T &any_cast(Any &&Value);
    template<class T>
    friend bool is_type(Any &value);
    template<class T>
    friend bool is_type(Any &&value);
    std::unique_ptr<HoldBase> holdbase_;
    std::type_index type_index_;

private:
    struct HoldBase
    {
        virtual ~HoldBase() = default;
        virtual std::unique_ptr<HoldBase> clone() const = 0;
    };

    template<typename T>
    struct Hold : public HoldBase
    {
    private:
        Hold &operator=(const Hold &other) = delete;
        Hold(const Hold &other) = delete;

    public:
        T value_;

    public:
        Hold(const T &value)
            : value_(value)
        {}
        Hold(T &&value)
            : value_(std::move(value))
        {}
        inline std::unique_ptr<HoldBase> clone() const override
        {
            return std::make_unique<Hold<T>>(value_);
        }
    };

public:
    Any(void)
        : type_index_(typeid(void))
    {}
    Any(const Any &other)
        : holdbase_(other.holdbase_ ? other.holdbase_->clone() : nullptr)
        , type_index_(other.type_index_)
    {}
    Any(Any &&other)
        : holdbase_(std::move(other.holdbase_))
        , type_index_(other.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)
        : holdbase_(new Hold<typename std::decay<T>::type>(std::forward<T>(value)))
        , type_index_(typeid(typename std::decay<T>::type))
    {}
    Any &operator=(Any &&other)
    {
        holdbase_ = std::move(other.holdbase_);
        type_index_ = other.type_index_;
        return *this;
    }
    Any &operator=(const Any &other)
    {
        if (other.holdbase_)
        {
            holdbase_ = other.holdbase_->clone();
            type_index_ = other.type_index_;
        }
        return *this;
    }
    Any &swap(Any &other)
    {
        std::swap(holdbase_, other.holdbase_);
        std::swap(type_index_, other.type_index_);
        return *this;
    }

    inline bool has_value() const
    {
        return !!holdbase_;
    }

    inline void reset()
    {
        holdbase_.reset();
        type_index_ = typeid(void);
    }

private:
    template<class T>
    inline bool Is() const
    {
        return type_index_ == typeid(T);
    }
    template<class T>
    inline T &any_cast()
    {
        if (!Is<T>())
        {
            if (type_index_ != typeid(void))
            {
                std::cout << "can not cast " << type_index_.name() << " to " << typeid(T).name() << std::endl;
            }
            throw std::bad_cast();
        }
        auto hold = dynamic_cast<Hold<T> *>(holdbase_.get());
        return hold->value_;
    }
};

template<class T>
T &any_cast(Any &value)
{
    return value.any_cast<T>();
}
template<class T>
T &any_cast(Any &&value)
{
    return value.any_cast<T>();
}
template<class T>
bool is_type(Any &&value)
{
    return value.Is<T>();
}
template<class T>
bool is_type(Any &value)
{
    return value.Is<T>();
}

// Usage
int main()
{
    int num = 7;
    Any a = num;
    int ret = any_cast<int>(a);
    std::cout << ret << std::endl;

    return 0;
}
本文由作者按照 CC BY 4.0 进行授权

© ziqing. 保留部分权利。

纸上得来终觉浅,绝知此事要躬行!