Boost.Any

考察一个特性,可以对比 不使用特性使用特性 完成业务功能的代码

Boost.Any 是为了满足 C++ 中需要存储任意类型数据的需求而设计的库。

一、Boost.Any 的设计目的

  1. 类型安全容器:在单个变量中存储任意类型的数据
  2. 运行时类型识别:允许在运行时检查存储的实际类型

二、没有 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:代码优化与工程级应用》祁宇

posted @ 2025-07-02 23:34  丘狸尾  阅读(24)  评论(0)    收藏  举报