<p>std::any 提供类型安全的任意值存储,解决 void* 类型不安全问题,通过运行时类型检查支持异构数据处理,适用于配置管理与事件系统等场景。</p>

在C++中,
std::any
void*
使用
std::any
首先,你需要包含
<any>
#include <iostream>
#include <any>
#include <string>
#include <vector>
int main() {
// 声明并初始化一个 std::any 对象
std::any myAnyValue; // 此时是空状态
// 存储一个整数
myAnyValue = 42;
std::cout << "存储了整数: " << std::any_cast<int>(myAnyValue) << std::endl;
// 存储一个字符串
myAnyValue = std::string("Hello, std::any!");
std::cout << "存储了字符串: " << std::any_cast<std::string>(myAnyValue) << std::endl;
// 存储一个自定义类型(例如,一个结构体或类实例)
struct MyData {
int id;
std::string name;
};
myAnyValue = MyData{1, "Test Data"};
// 取出时需要精确的类型
MyData data = std::any_cast<MyData>(myAnyValue);
std::cout << "存储了自定义类型: ID=" << data.id << ", Name=" << data.name << std::endl;
// 尝试取出不匹配的类型会导致 std::bad_any_cast 异常
try {
int x = std::any_cast<int>(myAnyValue); // myAnyValue 当前存储的是 MyData
std::cout << "尝试取出整数: " << x << std::endl; // 这行不会执行
} catch (const std::bad_any_cast& e) {
std::cerr << "捕获到异常: " << e.what() << std::endl;
}
// 检查 std::any 是否为空
std::any emptyAny;
if (!emptyAny.has_value()) {
std::cout << "emptyAny 当前为空。" << std::endl;
}
// 获取存储值的类型信息
myAnyValue = 3.14159;
std::cout << "当前存储值的类型名称: " << myAnyValue.type().name() << std::endl;
// 使用指针版本 std::any_cast,如果类型不匹配返回 nullptr
std::string* s_ptr = std::any_cast<std::string>(&myAnyValue);
if (s_ptr) {
std::cout << "通过指针取出了字符串: " << *s_ptr << std::endl;
} else {
std::cout << "通过指针取出字符串失败,类型不匹配。" << std::endl;
}
double* d_ptr = std::any_cast<double>(&myAnyValue);
if (d_ptr) {
std::cout << "通过指针取出了双精度浮点数: " << *d_ptr << std::endl;
}
return 0;
}代码中展示了
std::any
std::any_cast
std::bad_any_cast
has_value()
type()
立即学习“C++免费学习笔记(深入)”;
std::any
void*
在我看来,
std::any
过去,面对这种需求,我们可能会想到
void*
void*
void*
std::any
std::any
std::any_cast<T>
std::any
T
std::bad_any_cast
void*
std::any
任何工具都有其代价,
std::any
std::any
sizeof(void*) * 2
sizeof(void*) * 3
std::any
int
char
bool
std::any
std::any
另一个潜在的陷阱就是
std::bad_any_cast
std::any_cast
std::any_cast<T>(&any_obj)
nullptr
此外,
std::any
std::any
std::shared_ptr
std::unique_ptr
std::any
std::any
在实际项目中,
std::any
配置管理: 设想你需要一个配置系统,其中配置项的类型各不相同。传统的做法可能是一个巨大的
union
void*
std::any
#include <iostream>
#include <any>
#include <string>
#include <map>
#include <optional> // C++17
class ConfigManager {
public:
template<typename T>
void set(const std::string& key, const T& value) {
config_data_[key] = value;
std::cout << "设置配置项: " << key << " = " << value << std::endl;
}
template<typename T>
std::optional<T> get(const std::string& key) const {
auto it = config_data_.find(key);
if (it != config_data_.end()) {
try {
// 使用指针版本,避免异常,返回 optional
T* value_ptr = std::any_cast<T>(&it->second);
if (value_ptr) {
return *value_ptr;
}
} catch (const std::bad_any_cast& e) {
// 类型不匹配,但我们已经通过指针版本避免了直接异常,
// 这里的catch更多是防御性编程,以防万一或用于调试。
std::cerr << "配置项 '" << key << "' 类型不匹配: " << e.what() << std::endl;
}
}
return std::nullopt; // 未找到或类型不匹配
}
private:
std::map<std::string, std::any> config_data_;
};
// ... 在 main 函数中使用
// ConfigManager cm;
// cm.set("LogLevel", 3);
// cm.set("ServerAddress", std::string("192.168.1.100"));
// cm.set("EnableFeatureX", true);
// auto level = cm.get<int>("LogLevel");
// if (level) {
// std::cout << "获取 LogLevel: " << *level << std::endl;
// }
// auto address = cm.get<std::string>("ServerAddress");
// if (address) {
// std::cout << "获取 ServerAddress: " << *address << std::endl;
// }
// auto enabled = cm.get<bool>("EnableFeatureX");
// if (enabled) {
// std::cout << "获取 EnableFeatureX: " << std::boolalpha << *enabled << std::endl;
// }
// // 尝试获取不存在的配置项或类型不匹配的配置项
// auto nonExistent = cm.get<double>("NonExistentKey");
// if (!nonExistent) {
// std::cout << "NonExistentKey 未找到或类型不匹配。" << std::endl;
// }这个
ConfigManager
std::any
get
std::optional<T>
事件系统: 在事件驱动架构中,事件通常携带不同类型的数据。
std::any
#include <iostream>
#include <any>
#include <string>
#include <functional>
#include <map>
#include <vector>
// 假设我们有一个事件基类,或者只是一个事件类型枚举
enum class EventType {
UserLogin,
DataUpdate,
ErrorOccurred
};
struct UserLoginEventData {
std::string username;
int userId;
};
struct DataUpdateEventData {
std::string tableName;
int affectedRows;
};
// 事件总线
class EventBus {
public:
// 注册一个事件处理器
template<typename EventDataType>
void subscribe(EventType type, std::function<void(const EventDataType&)> handler) {
// 将类型擦除后的函数存储起来
// 这里需要一些技巧来存储不同类型的函数,通常会用一个lambda或std::bind
// 简单起见,我们直接存储一个包装了any_cast的lambda
handlers_[type].push_back([h = handler](const std::any& event_data) {
try {
h(std::any_cast<const EventDataType&>(event_data));
} catch (const std::bad_any_cast& e) {
std::cerr << "事件处理类型不匹配: " << e.what() << std::endl;
}
});
}
// 发布一个事件
template<typename EventDataType>
void publish(EventType type, const EventDataType& data) {
if (handlers_.count(type)) {
std::any event_any_data = data; // 将事件数据包装到 std::any 中
for (const auto& handler : handlers_[type]) {
handler(event_any_data);
}
}
}
private:
// 存储事件类型到其处理函数的映射
// 每个事件类型可以有多个处理函数
std::map<EventType, std::vector<std::function<void(const std::any&)>>> handlers_;
};
// ... 在 main 函数中使用
// EventBus bus;
// bus.subscribe<UserLoginEventData>(EventType::UserLogin, [](const UserLoginEventData& data) {
// std::cout << "[Event] 用户登录: " << data.username << " (ID: " << data.userId << ")" << std::endl;
// });
// bus.subscribe<DataUpdateEventData>(EventType::DataUpdate, [](const DataUpdateEventData& data) {
// std::cout << "[Event] 数据更新: 表 '" << data.tableName << "', 影响行数: " << data.affectedRows << std::endl;
// });
// // 发布事件
// bus.publish(EventType::UserLogin, UserLoginEventData{"Alice", 101});
// bus.publish(EventType::DataUpdate, DataUpdateEventData{"Products", 5});
// // 尝试发布错误类型的事件到错误的处理器 (这里会被 subscribe 内部的 try-catch 捕获)
// bus.publish(EventType::UserLogin, DataUpdateEventData{"Users", 1});在事件系统中,
std::any
EventBus
std::any
EventBus
std::any_cast
std::any
EventBus
std::any
以上就是如何在C++中使用std::any_C++ std::any类型安全容器用法的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号