类型擦除场景下能否在C++中用静态多态(模板)实现通用get方法?
C++11类型擦除下的通用动态变量与类型转换方案
核心思路
用类型擦除实现可存储任意类型的Variable类,通过模板化的get<T>方法统一访问接口,外部通过重载转换函数实现不同类型间的转换——新增类型或转换逻辑仅需添加对应转换函数,无需修改核心框架代码。
代码实现
1. 类型擦除核心框架
#include <memory> #include <typeindex> #include <stdexcept> #include <string> #include <vector> // 抽象基类,定义类型擦除的通用接口 class VariableConcept { public: virtual ~VariableConcept() = default; virtual std::unique_ptr<VariableConcept> clone() const = 0; virtual std::type_index type() const = 0; virtual void* get_ptr() = 0; virtual const void* get_const_ptr() const = 0; }; // 模板子类,存储具体类型的数据 template<typename T> class VariableImpl : public VariableConcept { public: explicit VariableImpl(T value) : value_(std::move(value)) {} std::unique_ptr<VariableConcept> clone() const override { return std::unique_ptr<VariableImpl<T>>(new VariableImpl<T>(value_)); } std::type_index type() const override { return typeid(T); } void* get_ptr() override { return &value_; } const void* get_const_ptr() const override { return &value_; } T& get() { return value_; } const T& get() const { return value_; } private: T value_; }; // 对外暴露的动态变量类 class Variable { public: // 构造任意类型的变量 template<typename T> Variable(T&& value) : impl_(std::unique_ptr<VariableImpl<typename std::decay<T>::type>>( new VariableImpl<typename std::decay<T>::type>(std::forward<T>(value)))) {} // 拷贝构造与赋值 Variable(const Variable& other) : impl_(other.impl_->clone()) {} Variable& operator=(const Variable& other) { if (this != &other) { impl_ = other.impl_->clone(); } return *this; } // 移动构造与赋值 Variable(Variable&&) = default; Variable& operator=(Variable&&) = default; // 获取存储类型的type_index std::type_index type() const { return impl_->type(); } // 通用模板get方法,支持直接获取或转换获取 template<typename T> T get() const { // 类型匹配时直接返回 if (type() == typeid(T)) { return static_cast<const VariableImpl<T>*>(impl_.get())->get(); } // 类型不匹配时分发到转换逻辑 return dispatch_convert<T>(*this); } private: std::unique_ptr<VariableConcept> impl_; // 类型分发辅助函数,根据存储类型调用对应转换函数 template<typename T> static T dispatch_convert(const Variable& var) { const auto stored_type = var.type(); if (stored_type == typeid(int)) { return convert(static_cast<const VariableImpl<int>*>(var.impl_.get())->get()); } if (stored_type == typeid(std::string)) { return convert(static_cast<const VariableImpl<std::string>*>(var.impl_.get())->get()); } if (stored_type == typeid(double)) { return convert(static_cast<const VariableImpl<double>*>(var.impl_.get())->get()); } if (stored_type == typeid(bool)) { return convert(static_cast<const VariableImpl<bool>*>(var.impl_.get())->get()); } throw std::runtime_error("No conversion available for stored type"); } // 声明转换函数为友元,允许访问内部存储 template<typename Target, typename Source> friend Target convert(const Source&); };
2. 扩展转换函数
新增转换逻辑仅需添加对应的convert重载,无需修改核心框架:
// int -> string std::string convert(int val) { return std::to_string(val); } // string -> int int convert(const std::string& s) { return std::stoi(s); } // double -> int int convert(double val) { return static_cast<int>(val); } // int -> double double convert(int val) { return static_cast<double>(val); } // bool -> string std::string convert(bool val) { return val ? "true" : "false"; } // 自定义类型示例:假设我们有一个Person类 struct Person { std::string name; int age; }; // Person -> string std::string convert(const Person& p) { return "Person: " + p.name + ", age: " + std::to_string(p.age); }
3. 使用示例
int main() { // 存储不同类型的变量 Variable var_int(42); Variable var_str("hello"); Variable var_double(3.14); Variable var_person(Person{"Alice", 30}); // 直接获取同类型值 int i = var_int.get<int>(); // 42 std::string s = var_str.get<std::string>(); // "hello" // 跨类型转换获取 std::string int_to_str = var_int.get<std::string>(); // "42" int str_to_int = var_str.get<int>(); // 抛出异常("hello"无法转int) int double_to_int = var_double.get<int>(); // 3 std::string person_str = var_person.get<std::string>(); // "Person: Alice, age: 30" // 存入容器 std::vector<Variable> vars; vars.push_back(var_int); vars.push_back(var_str); vars.push_back(var_person); for (const auto& var : vars) { try { std::string str = var.get<std::string>(); printf("Converted to string: %s\n", str.c_str()); } catch (const std::exception& e) { printf("Conversion failed: %s\n", e.what()); } } return 0; }
方案优势
- 符合C++11标准:不依赖第三方库,仅使用C++11特性实现
- 扩展性强:新增存储类型或转换目标仅需添加
convert重载函数,无需修改核心类 - 统一接口:通过模板
get<T>替代多个重载的get_xxx方法,调用更简洁 - 容器兼容:支持存入
std::vector等容器,满足动态集合需求
注意事项
- 转换函数需避免二义性:若多个源类型可转换为同一目标类型,需确保
convert重载的唯一性 - 自定义类型转换:只需为自定义类型实现对应的
convert重载即可纳入转换体系 - 异常处理:转换失败时会抛出
runtime_error,可根据需求调整异常类型或错误处理逻辑
内容的提问来源于stack exchange,提问作者hennejg
相关产品推荐
相关产品推荐

