c++如何实现一个variant c++ std::any的简化版【实例】

发布时间 - 2026-01-07 00:00:00    点击率:
简化版 variant 是轻量级 type-erased holder,支持有限类型集合的存储与安全取值;其核心由 void* 存储、type_info 类型标识和虚函数管理生命周期三要素构成,不追求完全兼容 std::variant 或 std::any。

什么是简化版 variant

我们不追求完全兼容 std::variantstd::any,而是实现一个轻量、可理解、支持有限类型集合的 type-erased holder,类似 std::any 的核心逻辑:能存任意给定类型(比如 intdoublestd::string),运行时知道当前存的是什么类型,并支持安全取值。

设计思路:用 void* + 类型 ID + 析构函数指针

关键三要素缺一不可:

  • 存储数据:用动态分配(或小对象优化,这里先用堆)+ void* 指向实际对象
  • 记录类型:用 std::type_info const* 或自定义类型 ID(推荐前者,直接且标准)
  • 管理生命周期:保存构造/拷贝/析构函数指针,确保对象被正确创建和销毁

代码实现(无依赖、C++11 可用)

下面是一个最小但完整可运行的简化版 my_any

#include 
#include 
#include 
#include 
#include 

class my_any { struct placeholder { virtual ~placeholder() = default; virtual const std::type_info& type() const = 0; virtual placeholder* clone() const = 0; virtual void destroy() = 0; };

templatezuojiankuohaophpcntypename Tyoujiankuohaophpcn
struct holder : placeholder {
    T value;
    holder(T&& v) : value(std::move(v)) {}
    holder(const T& v) : value(v) {}

    const std::type_info& type() const override { return typeid(T); }
    placeholder* clone() const override { return new holder(value); }
    void destroy() override { delete this; }
};

placeholder* ptr_ = nullptr;

public: my_any() = default;

templatezuojiankuohaophpcntypename Tyoujiankuohaophpcn
my_any(T&& v) : ptr_(new holder>(std::forward(v))) {}

my_any(const my_any& other) 
    : ptr_(other.ptr_ ? other.ptr_->clone() : nullptr) {}

my_any(my_any&& other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }

~my_any() { if (ptr_) ptr_->destroy(); }

my_any& operator=(const my_any& other) {
    if (this != &other) {
        if (ptr_) ptr_->destroy();
        ptr_ = other.ptr_ ? other.ptr_->clone() : nullptr;
    }
    return *this;
}

my_any& operator=(my_any&& other) noexcept {
    if (this != &other) {
        if (ptr_) ptr_->destroy();
        ptr_ = other.ptr_;
        other.ptr_ = nullptr;
    }
    return *this;
}

bool has_value() const { return ptr_ != nullptr; }

const std::type_info& type() const { 
    return ptr_ ? ptr_->type() : typeid(void); 
}

templatezuojiankuohaophpcntypename Tyoujiankuohaophpcn
T& get() & {
    if (!ptr_ || ptr_->type() != typeid(T))
        throw std::bad_cast();
    return static_castzuojiankuohaophpcnholderzuojiankuohaophpcnTyoujiankuohaophpcn*youjiankuohaophpcn(ptr_)->value;
}

templatezuojiankuohaophpcntypename Tyoujiankuohaophpcn
const T& get() const& {
    if (!ptr_ || ptr_->type() != typeid(T))
        throw std::bad_cast();
    return static_castzuojiankuohaophpcnholderzuojiankuohaophpcnTyoujiankuohaophpcn const*youjiankuohaophpcn(ptr_)->value;
}

};

使用示例

验证它能存、取、拷贝、移动不同类型:

int main() {
    my_any a = 42;
    std::cout << a.get() << "\n"; // 42
a = std::string("hello");
std::cout << a.getzuojiankuohaophpcnstd::stringyoujiankuohaophpcn() << "\n"; // hello

my_any b = a; // 拷贝构造
std::cout << b.getzuojiankuohaophpcnstd::stringyoujiankuohaophpcn() << "\n"; // hello

my_any c = std::move(a);
std::cout << c.getzuojiankuohaophpcnstd::stringyoujiankuohaophpcn() << "\n"; // hello
// a now empty — no crash on access
try {
    a.getzuojiankuohaophpcnstd::stringyoujiankuohaophpcn();
} catch (const std::bad_cast&) {
    std::cout << "a is empty or wrong type\n";
}

return 0;

}

关键点说明

这个简化版抓住了 std::any 的本质机制:

  • 所有类型擦除都靠 virtual 接口统一行为(clone/destroy/type
  • 模板 holder 在编译期为每种类型生成专属实现,避免运行时泛型开销
  • get 做运行时类型检查(typeid 对比),失败抛异常,不崩溃
  • 没有支持 std::any_cast 风格的指针版本,但加一层封装即可扩展

对比 std::any 的差异

原生 std::any 更健壮:支持小对象优化(SOO)、更严格的 SFINAE 约束、std::any_casthas_value() 返回 bool 而非空指针判断等。但本实现已覆盖最核心能力——类型擦除 + 安全访问 + RAII 管理,适合教学、嵌入式裁剪或理解原理。


# ai  # c++  # ios  # stream  # String  # 封装  # 析构函数  # const  # bool  # int  # double  # void  # 指针  # 虚函数  # 接口  #   # public  # 泛型  # 空指针  # 对象  # default  # 简化版  # 的是  # 是一个  # 擦除  # 自定义  # 而非  # 它能  # 先用  # 不同类型  # 期为 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 网站图片在线制作软件,怎么在图片上做链接?  Google浏览器为什么这么卡 Google浏览器提速优化设置步骤【方法】  关于BootStrap modal 在IOS9中不能弹出的解决方法(IOS 9 bootstrap modal ios 9 noticework)  Laravel如何记录日志_Laravel Logging系统配置与自定义日志通道  如何在香港免费服务器上快速搭建网站?  Laravel如何处理JSON字段的查询和更新_Laravel JSON列操作与查询技巧  香港服务器网站推广:SEO优化与外贸独立站搭建策略  如何选择可靠的免备案建站服务器?  如何用低价快速搭建高质量网站?  什么是javascript作用域_全局和局部作用域有什么区别?  深圳网站制作公司好吗,在深圳找工作哪个网站最好啊?  Python并发异常传播_错误处理解析【教程】  历史网站制作软件,华为如何找回被删除的网站?  Python自然语言搜索引擎项目教程_倒排索引查询优化案例  手机软键盘弹出时影响布局的解决方法  无锡营销型网站制作公司,无锡网选车牌流程?  黑客如何通过漏洞一步步攻陷网站服务器?  Laravel项目结构怎么组织_大型Laravel应用的最佳目录结构实践  ,南京靠谱的征婚网站?  购物网站制作费用多少,开办网上购物网站,需要办理哪些手续?  利用 Google AI 进行 YouTube 视频 SEO 描述优化  javascript基本数据类型及类型检测常用方法小结  如何在云虚拟主机上快速搭建个人网站?  如何在阿里云购买域名并搭建网站?  打造顶配客厅影院,这份100寸电视推荐名单请查收  千问怎样用提示词获取健康建议_千问健康类提示词注意事项【指南】  html5源代码发行怎么设置权限_访问权限控制方法与实践【指南】  Laravel如何使用withoutEvents方法临时禁用模型事件  HTML5空格和margin有啥区别_空格与外边距的使用场景【说明】  如何自定义建站之星网站的导航菜单样式?  免费的流程图制作网站有哪些,2025年教师初级职称申报网上流程?  浏览器如何快速切换搜索引擎_在地址栏使用不同搜索引擎【搜索】  Laravel如何实现数据导出到CSV文件_Laravel原生流式输出大数据量CSV【方案】  如何快速重置建站主机并恢复默认配置?  高端网站建设与定制开发一站式解决方案 中企动力  Laravel软删除怎么实现_Laravel Eloquent SoftDeletes功能使用教程  JavaScript如何操作视频_媒体API怎么控制播放  Laravel如何实现邮箱地址验证功能_Laravel邮件验证流程与配置  Laravel怎么解决跨域问题_Laravel配置CORS跨域访问  Android中Textview和图片同行显示(文字超出用省略号,图片自动靠右边)  如何在阿里云通过域名搭建网站?  Laravel怎么创建自己的包(Package)_Laravel扩展包开发入门到发布  UC浏览器如何设置启动页 UC浏览器启动页设置方法  laravel怎么通过契约(Contracts)编程_laravel契约(Contracts)编程方法  html5如何实现懒加载图片_ intersectionobserver api用法【教程】  如何用5美元大硬盘VPS安全高效搭建个人网站?  北京网站制作的公司有哪些,北京白云观官方网站?  Laravel Asset编译怎么配置_Laravel Vite前端构建工具使用  如何使用 Go 正则表达式精准提取括号内首个纯字母标识符(忽略数字与嵌套)  Laravel PHP版本要求一览_Laravel各版本环境要求对照