相关文章推荐
悲伤的墨镜  ·  python ...·  11 月前    · 
月球上的莲藕  ·  js ...·  11 月前    · 
潇洒的西瓜  ·  让你的 Python ...·  1 年前    · 

boost::any简介

C语言中有void*指针用于存放、传递任意类型数据,C++中呢?
boost库就提供了这样一个类:boost::any,一个很短小的类,主要作用是定义一个变量存放任意类型的数据。

boost::any用法

可以在存储的时候,将要存储的对象类型转换为boost::any类型,而要使用的时候,用boost::any_cast转型为相应的类型。
注意:转型的时候,只能转型为存储时的类型或者能隐式转换的类型,如果转换为不能兼容的类型,可能会导致未定义行为。

#include <boost/any.hpp>
#include <iostream>
#include <list>
#include <vector>
using namespace std;
int main()
    vector<boost::any> vec;
    list<int> lst = {4,5,6};
    vec.emplace_back(1);
    vec.emplace_back(string("hello"));
    vec.emplace_back(lst);
    int d = boost::any_cast<int>(vec[0]); // 将vec[0]转型为int
    cout << d << endl;
    const string &s = boost::any_cast<string&>(vec[1]); // 将vec[1]转型为string&
    cout << s << endl;
    const list<int>& tmpLst = boost::any_cast<list<int>&>(vec[2]); // 将vec[2转型为list<int>&
    for (auto const& e : tmpLst) {
        cout << e << ' ';
    cout << endl;
    return 0;

当我们不确定存储的any是何种类型时,可以利用RTTI技术typeid操作符进行判断

#include <boost/any.hpp>
#include <iostream>
#include <list>
#include <vector>
using namespace std;
int main()
    vector<boost::any> vec;
    list<int> lst = {4,5,6};
    vec.emplace_back(1);
    vec.emplace_back(string("hello"));
    vec.emplace_back(lst);
    vector<boost::any>::iterator it; // vector<boost::any>迭代器
    boost::any anyone;
    for (it = vec.begin(); it != vec.end(); ++it) {
        anyone = *it;
        if (anyone.type() == typeid(int)) { // typeid获取指定类型type_info类信息
            cout << boost::any_cast<int>(anyone) << endl;
        else if(anyone.type() == typeid(string)) {
            cout << boost::any_cast<string>(anyone) << endl;
        else {
            cout << "unknow type" << endl;
    return 0;

boost:any源码

实现any功能主要由三个部分组成:
1)any类;
2)内部类holder保存数据,其基类placeholder声明接口;
3)获取数据时,通过any_cast转型;

any 类及内部类holder

any class中实际存储用户实参的是指针成员content,content实际指向的是holder类型对象,而holder是一个内部类,其基类placeholder。

placeholder主要定义2个接口,用于帮助any获取content所指向的对象类型信息,以及深度克隆any成员content所指对象。
holder实现placeholder接口,非常重要一点是内部持有held,通过传入any实参拷贝构造或移动构造而来。也就是说,如果传入any的是右值,实参对象会移动构造held;如果传入any的是左值,实参对象会拷贝构造held。

1)传给any的实参必须是对象(或基本类型)本身,可以是左值,也可以是右值,但不能是地址,除非要通过any保存的是指针本身。

class any{    public: // structors
        // 一组构造函数
        any() BOOST_NOEXCEPT
          : content(0)
        template<typename ValueType>
        any(const ValueType & value)
          : content(new holder<ValueType>(value)) // 构造一个holder对象, 并由content接管
        any(const any & other)
          : content(other.content ? other.content->clone() : 0) // 拷贝other所指对象, 深度拷贝
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
        // Move constructor
        any(any&& other) BOOST_NOEXCEPT
          : content(other.content)
            other.content = 0;
        // Perfect forwarding of ValueType
        template<typename ValueType>
        any(ValueType&& value, typename boost::disable_if<boost::is_same<any&, ValueType> >::type* = 0)
          : content(new holder< typename remove_reference<ValueType>::type >(static_cast<ValueType&&>(value)))
#endif
        // 析构函数
        ~any() BOOST_NOEXCEPT
            delete content;
    public: // modifiers
        // swap成员函数
        any & swap(any & rhs) BOOST_NOEXCEPT
            std::swap(content, rhs.content);
            return *this;
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
        template<typename ValueType>
        any & operator=(const ValueType & rhs)
            any(rhs).swap(*this);
            return *this;
        any & operator=(any rhs)
            any(rhs).swap(*this);
            return *this;
#else
        any & operator=(const any& rhs)
            any(rhs).swap(*this);
            return *this;
        // move assignement
        any & operator=(any&& rhs) BOOST_NOEXCEPT
            rhs.swap(*this);
            any().swap(rhs);
            return *this;
        // Perfect forwarding of ValueType
        template <class ValueType>
        any & operator=(ValueType&& rhs)
            any(static_cast<ValueType&&>(rhs)).swap(*this);
            return *this;
#endif
    public: // queries
        bool empty() const BOOST_NOEXCEPT
            return !content;
        const std::type_info & type() const
            return content ? content->type() : typeid(void);
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
    private: // types
#else
    public: // types (public so any_cast can be non-friend)
#endif
        class placeholder
        public: // structors
            virtual ~placeholder()
        public: // queries
            // 获取类型信息
            virtual const std::type_info & type() const = 0;
            // 克隆对象
            virtual placeholder * clone() const = 0;
        template<typename ValueType>
        class holder : public placeholder
        public: // structors
            holder(const ValueType & value)
              : held(value) // 这里会发生拷贝构造, 通过value拷贝构造held
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
            holder(ValueType&& value)
              : held(static_cast< ValueType&& >(value)) // 这里会发生移动构造, 通过value移动构造held
#endif
        public: // queries
            // 获取ValueType的类型信息, 返回type_info对象
            virtual const std::type_info & type() const
                return typeid(ValueType);
            // 拷贝构造一个holder对象, 返回一个placeholder指针
            virtual placeholder * clone() const
                return new holder(held);
        public: // representation
            ValueType held; // held是对象类型, ValueType是要存储对象的原生类型, 通过模板参数传入
        private: // intentionally left unimplemented
            holder & operator=(const holder &); // 没有实现
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
    private: // representation
        template<typename ValueType>
        friend ValueType * any_cast(any *) BOOST_NOEXCEPT;
        template<typename ValueType>
        friend ValueType * unsafe_any_cast(any *) BOOST_NOEXCEPT;
#else
    public: // representation (public so any_cast can be non-friend)
#endif
        placeholder * content;

转型any_cast

any通过统一的placeholder类型指针content保存传入实参对象,那么当要使用时,如何知道取出并转换成所需类型呢?
boost为any提供转型操作any_cast<>,any_cast可以将any保存的对象转换成指定类型。

any_cast有多个重载版本,

//-----------------------------------------------------
// 一组any_cast函数模板
    // 参数是any*
    template<typename ValueType>
    ValueType * any_cast(any * operand) BOOST_NOEXCEPT
        // 当operand非空, 且所指对象类型名与 模板参数ValueType类型名相同时, 
        // 将operator所指对象用static_cast转型为模板参数对应的指针类型; 否则, 返回空指针
        return operand &&
#ifdef BOOST_AUX_ANY_TYPE_ID_NAME
            std::strcmp(operand->type().name(), typeid(ValueType).name()) == 0
#else
            operand->type() == typeid(ValueType)
#endif
            ? &static_cast<any::holder<ValueType> *>(operand->content)->held
    // 参数是const any*
    template<typename ValueType>
    inline const ValueType * any_cast(const any * operand) BOOST_NOEXCEPT
        return any_cast<ValueType>(const_cast<any *>(operand));
    // 参数是any&, 注意引用不能是空, 否则抛出异常
    // 由于返回值是ValueType, 会发生对operator代表对象的拷贝构造
    template<typename ValueType>
    ValueType any_cast(any & operand)
        // 定义内嵌类型nonref, 可用于去除引用(左值引用, 右值引用)
        typedef BOOST_DEDUCED_TYPENAME remove_reference<ValueType>::type nonref;
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
        // If 'nonref' is still reference type, it means the user has not
        // specialized 'remove_reference'.
        // Please use BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION macro
        // to generate specialization of remove_reference for your class
        // See type traits library documentation for details
        BOOST_STATIC_ASSERT(!is_reference<nonref>::value);
#endif
        // result是operand去除引用的指针类型
        nonref * result = any_cast<nonref>(&operand);
        if(!result)
            boost::throw_exception(bad_any_cast());
        return *result;
    // 参数是const any&
    template<typename ValueType>
    inline ValueType any_cast(const any & operand)
        typedef BOOST_DEDUCED_TYPENAME remove_reference<ValueType>::type nonref;
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
        // The comment in the above version of 'any_cast' explains when this
        // assert is fired and what to do.
        BOOST_STATIC_ASSERT(!is_reference<nonref>::value);
#endif
        // 将operator转型为const nonref& (这里ValueType是去除const, 引用后的ValueType)
        return any_cast<const nonref &>(const_cast<any &>(operand));

不安全转型unsafe_any_cast

类似于安全转型any_cast,但不做any实际存储对象类的与要转型的模板是否一致的类型验证。不推荐使用。

    // Note: The "unsafe" versions of any_cast are not part of the
    // public interface and may be removed at any time. They are
    // required where we know what type is stored in the any and can't
    // use typeid() comparison, e.g., when our types may travel across
    // different shared libraries.
    template<typename ValueType>
    inline ValueType * unsafe_any_cast(any * operand) BOOST_NOEXCEPT
        return &static_cast<any::holder<ValueType> *>(operand->content)->held;
    template<typename ValueType>
    inline const ValueType * unsafe_any_cast(const any * operand) BOOST_NOEXCEPT
        return unsafe_any_cast<ValueType>(const_cast<any *>(operand));

使用boost::any注意事项

虽说boost::any能存放任意类型,但调用了被存放对象的成员函数。如果被存放对象禁用copy操作,那么就不能直接存放对象本身,因为会调用被存放对象的copy构造函数。

且看下面代码:

#include "muduo/base/noncopyable.h"
#include <boost/any.hpp>
#include <iostream>
#include <memory>
using namespace std;
class Context : muduo::noncopyable // 禁用拷贝
public:
	Context(int val)
		: val_(val)
	void print()
		cout << "val = " << val_;
private:
	int val_;
int main()
	auto context = new Context(10);
	boost::any any = context;
	auto conn = boost::any_cast<Context>(&any);
	conn->print();
	return 0;

Context 类禁用拷贝,如果直接将context通过boost::any any = context;,会调用template<typename ValueType> any & operator=(const ValueType & rhs)

        template<typename ValueType>
        any & operator=(const ValueType & rhs)
            any(rhs).swap(*this); // 这里用rhs构造any,因此会调用any的构造函数
            return *this;

上面代码中,用rhs构造了临时对象any,因此会调用any的构造函数

        template<typename ValueType>
        any(const ValueType & value)
          : content(new holder<ValueType>(value)) // 构造一个holder对象, 并由content接管

注意到这里ValueType类型可以推导出来为Context类型,而new holder<ValueType>(value)会导致调用ValueType即Context的拷贝构造函数,而Context的拷贝构造函数已经禁用,这样做会导致错误,甚至程序崩溃。

解决办法:
将any存放对象由禁用拷贝到Context对象,改为指向Context对象的智能指针shared_ptr,来替代直接存放对象。

int main()
	shared_ptr<Context> context(new Context(10)); // 存放对象改为shared_ptr<>,允许拷贝
	boost::any any = context;
	auto conn = boost::any_cast<shared_ptr<Context>>(any);
	conn->print();
	return 0;

https://blog.csdn.net/u010216743/article/details/77772078
https://zhuanlan.zhihu.com/p/326781049