Boost.Any
考察一个特性,可以对比 不使用特性 和 使用特性 完成业务功能的代码
Boost.Any 是为了满足 C++ 中需要存储任意类型数据的需求而设计的库。
一、Boost.Any 的设计目的
- 类型安全容器:在单个变量中存储任意类型的数据
- 运行时类型识别:允许在运行时检查存储的实际类型
二、没有 Boost.Any 时的解决方案
使用 void* 指针(原始方式)
void* data = new int(42);
// 使用时需要手动转换并知道实际类型
int value = *static_cast<int*>(data);
delete static_cast<int*>(data);
缺点:
- 完全无类型安全
- 需要手动管理内存
- 无法在运行时检查类型
三、使用Boost.Any
#include <boost/any.hpp>
#include <iostream>
#include <string>
#include <vector>
void print_any(const boost::any& value) {
if (value.empty()) {
std::cout << "Empty any\n";
return;
}
if (value.type() == typeid(int)) {
std::cout << "int: " << boost::any_cast<int>(value) << '\n';
} else if (value.type() == typeid(double)) {
std::cout << "double: " << boost::any_cast<double>(value) << '\n';
} else if (value.type() == typeid(std::string)) {
std::cout << "string: " << boost::any_cast<std::string>(value) << '\n';
} else {
std::cout << "Unknown type: " << value.type().name() << '\n';
}
}
int main() {
// 1. 存储基本类型
boost::any a = 42;
print_any(a);
// 2. 存储字符串
a = std::string("Hello Boost.Any");
print_any(a);
// 3. 存储自定义类型
struct Point { int x, y; };
a = Point{10, 20};
try {
auto p = boost::any_cast<Point>(a);
std::cout << "Point: (" << p.x << ", " << p.y << ")\n";
} catch (const boost::bad_any_cast& e) {
std::cerr << "Cast failed: " << e.what() << '\n';
}
// 4. 类型安全检查
if (a.type() == typeid(Point)) {
std::cout << "a contains a Point\n";
}
// 5. 在容器中使用
std::vector<boost::any> hetero_vec;
hetero_vec.push_back(3.14);
hetero_vec.push_back(std::string("PI"));
hetero_vec.push_back(Point{1, 1});
for (const auto& item : hetero_vec) {
print_any(item);
}
return 0;
}
三、实现Boost.Any的关键技术
any能容纳所有类型的数据,因此,当赋值给any时,需要将值的类型擦除,即以一种通用的方式保存所有类型的数据。这里可以通过继承去擦除类型,基类是不含模板参数的,派生类中才有模板参数,这个模板参数类型正是赋值的类型。在赋值时,将创建的派生类对象赋值给基类指针,基类的派生类携带了数据类型,基类只是原始数据的一个占位符,通过多态的隐式转换擦除了原始数据类型,因此,任何数据类型都可以赋值给它,从而实现能存放所有类型数据的目标。当取数据时需要向下转换成派生类型来获取原始数据,当转换失败时打印详情,并抛出异常。由于向any赋值时需要创建一个派生类对象,所以还需要管理该对象的生命周期,这里用unique_ptr智能指针去管理对象的生命周期。
#include <memory>
#include <typeindex>
struct Any
{
Any(void) : m_tpIndex(std::type_index(typeid(void))){}
Any(Any& that) : m_ptr(that.Clone()), m_tpIndex(that.m_tpIndex) {}
Any(Any && that) : m_ptr(std::move(that.m_ptr)),
m_tpIndex(that.m_tpIndex) {}
// 创建智能指针时,对于一般的类型,通过std::decay来移除引用和cv符,从而获取原始类型
emplate<typename U, class = typename std::enable_if<!std::is_same<typename
std::decay<U>::type, Any>::value, U>::type> Any(U && value):m_ptr(new
Derived < typename std::decay<U>::type>(forward<U>(value))),m_tpIndex
(type_index(typeid(typename std::decay<U>::type))){}
bool IsNull() const { return !bool(m_ptr); }
template<class U> bool Is() const
{
return m_tpIndex == type_index(typeid(U));
}
// 将Any转换为实际的类型
template<class U>
U& AnyCast()
{
if (!Is<U>())
{
cout << "can not cast " << typeid(U).name() << " to "
<< m_tpIndex.name() << endl;
throw bad_cast();
}
auto derived = dynamic_cast<Derived<U>*> (m_ptr.get());
return derived->m_value;
}
Any& operator=(const Any& a)
{
if (m_ptr == a.m_ptr)
return *this;
m_ptr = a.Clone();
m_tpIndex = a.m_tpIndex;
return *this;
}
private:
struct Base;
typedef std::unique_ptr<Base> BasePtr;
struct Base
{
virtual ~Base() {}
virtual BasePtr Clone() const = 0;
};
template<typename T>
struct Derived : Base
{
template<typename U>
Derived(U && value) : m_value(forward<U>(value)) { }
BasePtr Clone() const
{
return BasePtr(new Derived<T>(m_value));
}
T m_value;
};
BasePtr Clone() const
{
if (m_ptr != nullptr)
return m_ptr->Clone();
return nullptr;
}
BasePtr m_ptr;
std::type_index m_tpIndex;
};
《深入应用C++11:代码优化与工程级应用》祁宇

浙公网安备 33010602011771号