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

什么是简化版 variant
我们不追求完全兼容 std::variant 或 std::any,而是实现一个轻量、可理解、支持有限类型集合的 type-erased holder,类似 std::any 的核心逻辑:能存任意给定类型(比如 int、double、std::string),运行时知道当前存的是什么类型,并支持安全取值。
设计思路:用 void* + 类型 ID + 析构函数指针
关键三要素缺一不可:
-
存储数据:用动态分配(或小对象优化,这里先用堆)+
void*指向实际对象 -
记录类型:用
std::type_info const*或自定义类型 ID(推荐前者,直接且标准) - 管理生命周期:保存构造/拷贝/析构函数指针,确保对象被正确创建和销毁
代码实现(无依赖、C++11 可用)
下面是一个最小但完整可运行的简化版 my_any:
立即学习“C++免费学习笔记(深入)”;
#include <iostream>
#include <typeinfo>
#include <typeindex>
#include <memory>
#include <string>
<p>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;
};</p><pre class='brush:php;toolbar:false;'>template<typename T>
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<T>(value); }
void destroy() override { delete this; }
};
placeholder* ptr_ = nullptr;public: my_any() = default;
template<typename T>
my_any(T&& v) : ptr_(new holder<std::decay_t<T>>(std::forward<T>(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);
}
template<typename T>
T& get() & {
if (!ptr_ || ptr_->type() != typeid(T))
throw std::bad_cast();
return static_cast<holder<T>*>(ptr_)->value;
}
template<typename T>
const T& get() const& {
if (!ptr_ || ptr_->type() != typeid(T))
throw std::bad_cast();
return static_cast<holder<T> const*>(ptr_)->value;
}};
使用示例
验证它能存、取、拷贝、移动不同类型:
立即学习“C++免费学习笔记(深入)”;
int main() {
my_any a = 42;
std::cout << a.get<int>() << "\n"; // 42
<pre class='brush:php;toolbar:false;'>a = std::string("hello");
std::cout << a.get<std::string>() << "\n"; // hello
my_any b = a; // 拷贝构造
std::cout << b.get<std::string>() << "\n"; // hello
my_any c = std::move(a);
std::cout << c.get<std::string>() << "\n"; // hello
// a now empty — no crash on access
try {
a.get<std::string>();
} catch (const std::bad_cast&) {
std::cout << "a is empty or wrong type\n";
}
return 0;}
关键点说明
这个简化版抓住了 std::any 的本质机制:
- 所有类型擦除都靠
virtual接口统一行为(clone/destroy/type) - 模板
holder<T>在编译期为每种类型生成专属实现,避免运行时泛型开销 -
get<T>做运行时类型检查(typeid对比),失败抛异常,不崩溃 - 没有支持
std::any_cast风格的指针版本,但加一层封装即可扩展
对比 std::any 的差异
原生 std::any 更健壮:支持小对象优化(SOO)、更严格的 SFINAE 约束、std::any_cast<T*>、has_value() 返回 bool 而非空指针判断等。但本实现已覆盖最核心能力——类型擦除 + 安全访问 + RAII 管理,适合教学、嵌入式裁剪或理解原理。








