C++学习笔记-Any

std::any是C++17引入的类型擦除容器,可以存储任何可拷贝构造的类型的值。与variant不同,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
#include <iostream>
#include <any>
#include <string>
#include <vector>

void BasicAnyUsage()
{
    std::cout << "=== Basic Any Usage ===" << std::endl;
    
    // 创建any对象
    std::any data;
    
    // 存储不同类型的值
    data = 42;
    std::cout << "Stored int: " << std::any_cast<int>(data) << std::endl;
    
    data = 3.14;
    std::cout << "Stored double: " << std::any_cast<double>(data) << std::endl;
    
    data = std::string("Hello Any!");
    std::cout << "Stored string: " << std::any_cast<std::string>(data) << std::endl;
    
    // 检查是否有值
    if (data.has_value())
    {
        std::cout << "Any has value" << std::endl;
        std::cout << "Type: " << data.type().name() << std::endl;
    }
    
    // 重置any
    data.reset();
    std::cout << "After reset, has value: " << data.has_value() << std::endl;
    
    // 使用emplace
    data.emplace<std::vector<int>>(std::initializer_list<int>{1, 2, 3, 4, 5});
    auto& vec = std::any_cast<std::vector<int>&>(data);
    std::cout << "Vector size: " << vec.size() << std::endl;
}

void TypeCheckingDemo()
{
    std::cout << "\n=== Type Checking Demo ===" << std::endl;
    
    std::any data = 42;
    
    // 安全的类型转换
    try
    {
        int value = std::any_cast<int>(data);
        std::cout << "Successfully cast to int: " << value << std::endl;
    }
    catch (const std::bad_any_cast& e)
    {
        std::cout << "Failed to cast to int: " << e.what() << std::endl;
    }
    
    // 尝试错误的类型转换
    try
    {
        std::string value = std::any_cast<std::string>(data);
        std::cout << "Successfully cast to string: " << value << std::endl;
    }
    catch (const std::bad_any_cast& e)
    {
        std::cout << "Failed to cast to string: " << e.what() << std::endl;
    }
    
    // 使用指针版本的any_cast(不抛异常)
    if (int* intPtr = std::any_cast<int>(&data))
    {
        std::cout << "Pointer cast to int successful: " << *intPtr << std::endl;
    }
    else
    {
        std::cout << "Pointer cast to int failed" << std::endl;
    }
    
    if (std::string* stringPtr = std::any_cast<std::string>(&data))
    {
        std::cout << "Pointer cast to string successful: " << *stringPtr << std::endl;
    }
    else
    {
        std::cout << "Pointer cast to string failed" << std::endl;
    }
}

int main()
{
    BasicAnyUsage();
    TypeCheckingDemo();
    return 0;
}

实际应用场景

  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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#include <iostream>
#include <any>
#include <string>
#include <map>
#include <vector>
#include <typeinfo>

// 配置系统
class ConfigManager
{
private:
    std::map<std::string, std::any> m_Config;
    
public:
    template<typename T>
    void Set(const std::string& key, const T& value)
    {
        m_Config[key] = value;
    }
    
    template<typename T>
    T Get(const std::string& key) const
    {
        auto it = m_Config.find(key);
        if (it != m_Config.end())
        {
            try
            {
                return std::any_cast<T>(it->second);
            }
            catch (const std::bad_any_cast&)
            {
                throw std::runtime_error("Type mismatch for key: " + key);
            }
        }
        throw std::runtime_error("Key not found: " + key);
    }
    
    template<typename T>
    T GetOr(const std::string& key, const T& defaultValue) const
    {
        try
        {
            return Get<T>(key);
        }
        catch (...)
        {
            return defaultValue;
        }
    }
    
    bool HasKey(const std::string& key) const
    {
        return m_Config.find(key) != m_Config.end();
    }
    
    std::string GetTypeName(const std::string& key) const
    {
        auto it = m_Config.find(key);
        if (it != m_Config.end())
        {
            return it->second.type().name();
        }
        return "unknown";
    }
    
    void PrintAll() const
    {
        std::cout << "Configuration:" << std::endl;
        for (const auto& [key, value] : m_Config)
        {
            std::cout << "  " << key << " (" << value.type().name() << ")" << std::endl;
        }
    }
};

// 事件系统
struct Event
{
    std::string type;
    std::any data;
    
    Event(const std::string& t) : type(t) {}
    
    template<typename T>
    Event(const std::string& t, const T& d) : type(t), data(d) {}
    
    template<typename T>
    T GetData() const
    {
        return std::any_cast<T>(data);
    }
    
    template<typename T>
    bool IsDataType() const
    {
        return data.type() == typeid(T);
    }
};

class EventManager
{
private:
    std::vector<Event> m_Events;
    
public:
    template<typename T>
    void Emit(const std::string& type, const T& data)
    {
        m_Events.emplace_back(type, data);
        std::cout << "Event emitted: " << type << std::endl;
    }
    
    void Emit(const std::string& type)
    {
        m_Events.emplace_back(type);
        std::cout << "Event emitted: " << type << std::endl;
    }
    
    std::vector<Event> GetEvents(const std::string& type) const
    {
        std::vector<Event> result;
        for (const auto& event : m_Events)
        {
            if (event.type == type)
            {
                result.push_back(event);
            }
        }
        return result;
    }
    
    void ProcessEvents()
    {
        for (const auto& event : m_Events)
        {
            std::cout << "Processing event: " << event.type;
            if (event.data.has_value())
            {
                std::cout << " (data type: " << event.data.type().name() << ")";
            }
            std::cout << std::endl;
        }
        m_Events.clear();
    }
};

// 数据容器
class DataContainer
{
private:
    std::vector<std::any> m_Data;
    
public:
    template<typename T>
    void Add(const T& value)
    {
        m_Data.push_back(value);
    }
    
    size_t Size() const { return m_Data.size(); }
    
    template<typename T>
    std::vector<T> GetAll() const
    {
        std::vector<T> result;
        for (const auto& item : m_Data)
        {
            if (T* ptr = std::any_cast<T>(&item))
            {
                result.push_back(*ptr);
            }
        }
        return result;
    }
    
    void PrintTypes() const
    {
        std::cout << "Container types:" << std::endl;
        for (size_t i = 0; i < m_Data.size(); ++i)
        {
            std::cout << "  [" << i << "]: " << m_Data[i].type().name() << std::endl;
        }
    }
    
    template<typename Visitor>
    void Visit(Visitor&& visitor) const
    {
        for (const auto& item : m_Data)
        {
            // 尝试不同的类型
            if (const int* intPtr = std::any_cast<int>(&item))
            {
                visitor(*intPtr);
            }
            else if (const double* doublePtr = std::any_cast<double>(&item))
            {
                visitor(*doublePtr);
            }
            else if (const std::string* stringPtr = std::any_cast<std::string>(&item))
            {
                visitor(*stringPtr);
            }
            else
            {
                visitor("unknown type");
            }
        }
    }
};

void PracticalExamplesDemo()
{
    std::cout << "=== Practical Examples Demo ===" << std::endl;
    
    // 配置管理器示例
    std::cout << "1. Configuration Manager:" << std::endl;
    ConfigManager config;
    
    config.Set("window_width", 1920);
    config.Set("window_height", 1080);
    config.Set("fullscreen", true);
    config.Set("title", std::string("My Application"));
    config.Set("version", 1.5);
    
    config.PrintAll();
    
    std::cout << "Window size: " << config.Get<int>("window_width") 
              << "x" << config.Get<int>("window_height") << std::endl;
    std::cout << "Fullscreen: " << (config.Get<bool>("fullscreen") ? "yes" : "no") << std::endl;
    std::cout << "Title: " << config.Get<std::string>("title") << std::endl;
    
    // 使用默认值
    auto timeout = config.GetOr<int>("timeout", 30);
    std::cout << "Timeout: " << timeout << " seconds" << std::endl;
    
    // 事件系统示例
    std::cout << "\n2. Event System:" << std::endl;
    EventManager eventMgr;
    
    eventMgr.Emit("user_login", std::string("john_doe"));
    eventMgr.Emit("score_update", 1500);
    eventMgr.Emit("level_complete");
    eventMgr.Emit("item_collected", std::string("health_potion"));
    
    eventMgr.ProcessEvents();
    
    // 数据容器示例
    std::cout << "\n3. Data Container:" << std::endl;
    DataContainer container;
    
    container.Add(42);
    container.Add(3.14);
    container.Add(std::string("Hello"));
    container.Add(100);
    container.Add(std::string("World"));
    
    container.PrintTypes();
    
    auto integers = container.GetAll<int>();
    auto strings = container.GetAll<std::string>();
    
    std::cout << "Integers: ";
    for (int i : integers) std::cout << i << " ";
    std::cout << std::endl;
    
    std::cout << "Strings: ";
    for (const auto& s : strings) std::cout << s << " ";
    std::cout << std::endl;
    
    std::cout << "All items: ";
    container.Visit([](const auto& item) {
        std::cout << item << " ";
    });
    std::cout << std::endl;
}

int main()
{
    PracticalExamplesDemo();
    return 0;
}

性能考虑和限制

  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
#include <iostream>
#include <any>
#include <variant>
#include <chrono>
#include <vector>

// 性能测试
void PerformanceComparison()
{
    std::cout << "=== Performance Comparison ===" << std::endl;
    
    const int iterations = 1000000;
    
    // std::any性能测试
    auto start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < iterations; ++i)
    {
        std::any data = i;
        volatile int value = std::any_cast<int>(data);
    }
    auto end = std::chrono::high_resolution_clock::now();
    auto anyTime = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    
    // std::variant性能测试
    start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < iterations; ++i)
    {
        std::variant<int, double, std::string> data = i;
        volatile int value = std::get<int>(data);
    }
    end = std::chrono::high_resolution_clock::now();
    auto variantTime = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    
    // 原始类型性能测试
    start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < iterations; ++i)
    {
        int data = i;
        volatile int value = data;
    }
    end = std::chrono::high_resolution_clock::now();
    auto rawTime = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    
    std::cout << "Raw type: " << rawTime.count() << " ms" << std::endl;
    std::cout << "std::variant: " << variantTime.count() << " ms" << std::endl;
    std::cout << "std::any: " << anyTime.count() << " ms" << std::endl;
    
    std::cout << "std::any is " << (double)anyTime.count() / rawTime.count() << "x slower than raw" << std::endl;
    std::cout << "std::variant is " << (double)variantTime.count() / rawTime.count() << "x slower than raw" << std::endl;
}

// 内存使用测试
void MemoryUsageDemo()
{
    std::cout << "\n=== Memory Usage Demo ===" << std::endl;
    
    std::cout << "Size comparison:" << std::endl;
    std::cout << "int: " << sizeof(int) << " bytes" << std::endl;
    std::cout << "double: " << sizeof(double) << " bytes" << std::endl;
    std::cout << "std::string: " << sizeof(std::string) << " bytes" << std::endl;
    
    std::any anyInt = 42;
    std::any anyDouble = 3.14;
    std::any anyString = std::string("Hello");
    
    std::cout << "std::any (int): " << sizeof(anyInt) << " bytes" << std::endl;
    std::cout << "std::any (double): " << sizeof(anyDouble) << " bytes" << std::endl;
    std::cout << "std::any (string): " << sizeof(anyString) << " bytes" << std::endl;
    
    std::variant<int, double, std::string> variantInt = 42;
    std::variant<int, double, std::string> variantDouble = 3.14;
    std::variant<int, double, std::string> variantString = std::string("Hello");
    
    std::cout << "std::variant (int): " << sizeof(variantInt) << " bytes" << std::endl;
    std::cout << "std::variant (double): " << sizeof(variantDouble) << " bytes" << std::endl;
    std::cout << "std::variant (string): " << sizeof(variantString) << " bytes" << std::endl;
}

// 类型限制演示
void TypeLimitationsDemo()
{
    std::cout << "\n=== Type Limitations Demo ===" << std::endl;
    
    // std::any要求类型是可拷贝构造的
    struct NonCopyable
    {
        NonCopyable() = default;
        NonCopyable(const NonCopyable&) = delete;
        NonCopyable& operator=(const NonCopyable&) = delete;
        NonCopyable(NonCopyable&&) = default;
        NonCopyable& operator=(NonCopyable&&) = default;
    };
    
    // 这会编译失败
    // std::any data = NonCopyable{};
    
    // 可以存储可拷贝的类型
    struct Copyable
    {
        int value;
        Copyable(int v) : value(v) {}
    };
    
    std::any data = Copyable{42};
    auto obj = std::any_cast<Copyable>(data);
    std::cout << "Copyable object value: " << obj.value << std::endl;
    
    // 引用类型的处理
    int x = 100;
    std::any refData = std::ref(x);  // 存储引用包装器
    auto& ref = std::any_cast<std::reference_wrapper<int>&>(refData);
    ref.get() = 200;
    std::cout << "Modified through reference: " << x << std::endl;
}

// 最佳实践
void BestPracticesDemo()
{
    std::cout << "\n=== Best Practices Demo ===" << std::endl;
    
    std::cout << "1. Use std::any when you need to store truly arbitrary types" << std::endl;
    std::cout << "2. Prefer std::variant when you know the possible types" << std::endl;
    std::cout << "3. Always use exception handling or pointer-based any_cast" << std::endl;
    std::cout << "4. Consider performance implications - any has overhead" << std::endl;
    std::cout << "5. Document expected types when using any in APIs" << std::endl;
    std::cout << "6. Use type traits to constrain template parameters when needed" << std::endl;
    
    // 安全的any使用模式
    auto safeAnyCast = [](const std::any& data, const std::string& expectedType) -> bool {
        try
        {
            if (expectedType == "int")
            {
                int value = std::any_cast<int>(data);
                std::cout << "Safe cast to int: " << value << std::endl;
                return true;
            }
            else if (expectedType == "string")
            {
                std::string value = std::any_cast<std::string>(data);
                std::cout << "Safe cast to string: " << value << std::endl;
                return true;
            }
        }
        catch (const std::bad_any_cast& e)
        {
            std::cout << "Cast failed: " << e.what() << std::endl;
            return false;
        }
        return false;
    };
    
    std::any data1 = 42;
    std::any data2 = std::string("Hello");
    
    safeAnyCast(data1, "int");
    safeAnyCast(data1, "string");
    safeAnyCast(data2, "string");
    safeAnyCast(data2, "int");
}

int main()
{
    PerformanceComparison();
    MemoryUsageDemo();
    TypeLimitationsDemo();
    BestPracticesDemo();
    
    return 0;
}

与其他类型擦除技术的比较

  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
#include <iostream>
#include <any>
#include <variant>
#include <memory>
#include <functional>

// 传统的void*方法
class VoidPtrContainer
{
private:
    void* m_Data;
    std::function<void(void*)> m_Deleter;
    
public:
    template<typename T>
    VoidPtrContainer(const T& value)
    {
        m_Data = new T(value);
        m_Deleter = [](void* ptr) { delete static_cast<T*>(ptr); };
    }
    
    ~VoidPtrContainer()
    {
        if (m_Data && m_Deleter)
        {
            m_Deleter(m_Data);
        }
    }
    
    template<typename T>
    T* Get()
    {
        return static_cast<T*>(m_Data);
    }
};

// 基于继承的类型擦除
class TypeErasedBase
{
public:
    virtual ~TypeErasedBase() = default;
    virtual void Print() const = 0;
    virtual std::unique_ptr<TypeErasedBase> Clone() const = 0;
};

template<typename T>
class TypeErasedImpl : public TypeErasedBase
{
private:
    T m_Value;
    
public:
    TypeErasedImpl(const T& value) : m_Value(value) {}
    
    void Print() const override
    {
        std::cout << m_Value;
    }
    
    std::unique_ptr<TypeErasedBase> Clone() const override
    {
        return std::make_unique<TypeErasedImpl<T>>(m_Value);
    }
    
    const T& GetValue() const { return m_Value; }
};

class TypeErasedContainer
{
private:
    std::unique_ptr<TypeErasedBase> m_Impl;
    
public:
    template<typename T>
    TypeErasedContainer(const T& value)
        : m_Impl(std::make_unique<TypeErasedImpl<T>>(value)) {}
    
    TypeErasedContainer(const TypeErasedContainer& other)
        : m_Impl(other.m_Impl ? other.m_Impl->Clone() : nullptr) {}
    
    TypeErasedContainer& operator=(const TypeErasedContainer& other)
    {
        if (this != &other)
        {
            m_Impl = other.m_Impl ? other.m_Impl->Clone() : nullptr;
        }
        return *this;
    }
    
    void Print() const
    {
        if (m_Impl)
        {
            m_Impl->Print();
        }
    }
    
    template<typename T>
    const T* Get() const
    {
        if (auto* impl = dynamic_cast<const TypeErasedImpl<T>*>(m_Impl.get()))
        {
            return &impl->GetValue();
        }
        return nullptr;
    }
};

void ComparisonDemo()
{
    std::cout << "=== Type Erasure Comparison ===" << std::endl;
    
    // std::any方法
    std::cout << "1. std::any approach:" << std::endl;
    std::any anyData = 42;
    try
    {
        int value = std::any_cast<int>(anyData);
        std::cout << "   Value: " << value << std::endl;
    }
    catch (const std::bad_any_cast& e)
    {
        std::cout << "   Cast failed: " << e.what() << std::endl;
    }
    
    // void*方法(不推荐)
    std::cout << "\n2. void* approach (not recommended):" << std::endl;
    VoidPtrContainer voidData(42);
    if (int* ptr = voidData.Get<int>())
    {
        std::cout << "   Value: " << *ptr << std::endl;
    }
    
    // 基于继承的类型擦除
    std::cout << "\n3. Inheritance-based type erasure:" << std::endl;
    TypeErasedContainer container1(42);
    TypeErasedContainer container2(std::string("Hello"));
    
    std::cout << "   Container1: ";
    container1.Print();
    std::cout << std::endl;
    
    std::cout << "   Container2: ";
    container2.Print();
    std::cout << std::endl;
    
    if (const int* intPtr = container1.Get<int>())
    {
        std::cout << "   Retrieved int: " << *intPtr << std::endl;
    }
    
    if (const std::string* stringPtr = container2.Get<std::string>())
    {
        std::cout << "   Retrieved string: " << *stringPtr << std::endl;
    }
    
    // std::variant方法
    std::cout << "\n4. std::variant approach:" << std::endl;
    std::variant<int, double, std::string> variantData = 42;
    std::visit([](const auto& value) {
        std::cout << "   Value: " << value << std::endl;
    }, variantData);
    
    std::cout << "\nComparison summary:" << std::endl;
    std::cout << "- std::any: Most flexible, runtime overhead, type-safe" << std::endl;
    std::cout << "- void*: Fastest, no type safety, manual memory management" << std::endl;
    std::cout << "- Inheritance: Good performance, requires virtual functions" << std::endl;
    std::cout << "- std::variant: Fast, compile-time type list, type-safe" << std::endl;
}

int main()
{
    ComparisonDemo();
    return 0;
}

总结

  1. std::any基础:C++17的类型擦除容器,可以存储任何可拷贝构造的类型
  2. 主要特点
    • 运行时类型擦除
    • 类型安全的访问
    • 自动内存管理
    • 支持任意可拷贝类型
  3. 访问方法
    • std::any_cast<T>():直接转换(可能抛异常)
    • std::any_cast<T*>():指针转换(返回nullptr表示失败)
    • has_value():检查是否有值
    • type():获取类型信息
  4. 实际应用
    • 配置系统
    • 事件系统
    • 插件架构
    • 通用数据容器
  5. 性能考虑
    • 比原始类型慢(动态分配和类型检查)
    • 比void*安全但更慢
    • 比std::variant更灵活但更慢
  6. 最佳实践
    • 需要真正任意类型时使用
    • 已知类型集合时优先使用variant
    • 总是进行异常处理或使用指针版本
    • 注意性能影响
    • 文档化预期类型
updatedupdated2025-09-202025-09-20