alex

alex

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  7 随笔 :: 6 文章 :: 7 评论 :: 0 Trackbacks

前几天一个朋友给我看了1段代码:
any temp; //any is a class
temp = 1;
temp = "a";
temp = x; //x is a abstract class

看到这段代码着实下了1跳.初期的感觉象void*指针那样,又象variant变量。但感觉还是比较新颖的,-_-''也许我是菜鸟的原因,在脑袋转了一下后,我实现了自己的一个类,用来接受任何参数,起初我认为any应该是个typedef,而接收的类型也是前面知道的(-_-''又没弄清需求就去实现了),所以实现一个接收任何参数的类需要个typelist,和对每种类型的泛化,下面是class的定义:

template<typename _typelist>
class any
{
public:
 typedef typename Loki::TL::TypeAtNonStrict<_typelist,0>::Result param1;
 typedef typename Loki::TL::TypeAtNonStrict<_typelist,1>::Result param2;
 typedef typename Loki::TL::TypeAtNonStrict<_typelist,2>::Result param3;
 typedef typename Loki::TL::TypeAtNonStrict<_typelist,3>::Result param4;
 typedef typename Loki::TL::TypeAtNonStrict<_typelist,4>::Result param5;

 any(param1 param):
  m_param1(param){}

 any(param2 param):
  m_param2(param){}

 any(param3 param):
  m_param3(param){}

 any(param4 param):
  m_param4(param){}

 template<typename _Ty>
 const _Ty&  Get()
 {
     class CERROR_ACCESS_DENIED;
     LOKI_STATIC_CHECK((Loki::TL::IndexOf<_typelist,_Ty>::value != -     1),CERROR_ACCESS_DENIED);

     return __Access<_Ty>();
 }
private:
 template<typename _Ty>
 _Ty&  __Access();

 template<>
 param1& __Access<param1>() {return m_param1;}

 template<>
 param2& __Access<param2>() {return m_param2;}

 template<>
 param3& __Access<param3>() {return m_param3;}

 template<>
 param4& __Access<param4>() {return m_param4;}

 param1  m_param1;
 param2  m_param2;
 param3  m_param3;
 param4  m_param4;
};

typedef any<Loki::TYPE_LIST_3(int,float,char)> ANY;

这样似乎就可以接收任何类型了,也可以取出数据,取出时必须要知道相应的类型,而且,假如类型不在列表里面,则编译期出错
class CERROR_ACCESS_DENIED;
LOKI_STATIC_CHECK((Loki::TL::IndexOf<_typelist,_Ty>::value != -     1),CERROR_ACCESS_DENIED);
这样,-_-''似乎就可以了,只要所接收的类型可以拷贝即可。但有个明了的缺陷,那1就是接收的类型必须编译期写死,假如不写死的话,我个人开始的认为是加一个基类,-_-''
还是要3q我那位朋友,让我了解到boost::any的用法
下面是boost::any的具体分析,我们要达到下面几个要求:
1:可以接收任何类型的数据(具有value属性)
2: 可以方便的取出数据
3:型别安全,不象void*
下面是boost::any的实现,我按部分贴,而且省去我认为不重要的东西,因为太长了,这会影响我blog的收视率。
1:首先来看下他的构造和稀构(-_-''错别字)
 any()
    : content(0)
{
}
 
 template<typename ValueType>
 any(const ValueType & value)
    : content(new holder<ValueType>(value))
{
}
 
any(const any & other)
    : content(other.content ? other.content->clone() : 0)
 {
 }
 
 ~any()
 {
     delete content;
 }
从构造函数可以看到,any可以接受默认的,任何其他值包括ant本身,在稀构里面可以看到对content的释放,content在这里是一个基类的指针,是any内部实现的,我们可以看到,在对any构造是有种方法:
(1)content(new holder<ValueType>(value))
(2)content(other.content ? other.content->clone() : 0)
稍后会看到holder是派生自content类型的一个模板实现,也许讲到这里,有些应该明白了any是怎么保存任何类型的吧,对于其他any的构造,我们发现调用了content的一个clone方法,很明显这是content的一个虚方法,这个方法的存在得以让我们运用虚函数的机制正确的拷贝对象,下面会看到这只是个简单的new操作。
2:来看下any的operator =的重载
any & swap(any & rhs)
{
     std::swap(content, rhs.content);
     return *this;
}
 
template<typename ValueType>
any & operator=(const ValueType & rhs)
{
    any(rhs).swap(*this);
    return *this;
}
 
any & operator=(const any & rhs)
{
      any(rhs).swap(*this);
      return *this;
}
可以看到operator =,接收任何其他类型的参数,swap方法的实现,用来交换2个对象的content指针,我们可以看到operator =里面临时对象的构建,在函数结束后,自动释放原来content的对象,这有点RAII味道。(http://blog.sina.com.cn/u/1019039487)独家小菜。。
3:下面来看下辅助类
 bool empty() const
 {
      return !content;
 }
 
 const std::type_info & type() const
 {
      return content ? content->type() : typeid(void);
 }
可以看到。一个empty,一个type,很形象。
4:下面来看下上面content所指的对象,以及any怎么保存任何类型,以及这种怎么保证型别安全
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)
     {
     }
public: // queries
     virtual const std::type_info & type() const
     {
         return typeid(ValueType);
     }
 
     virtual placeholder * clone() const
     {
          return new holder(held);
     }
public: // representation
     ValueType held;
};(-_-''格式矫正真是类啊)
 
placeholder就是上面content指向的对象,可以看到他定义的一些提供给any调用的函数和虚基本必须的虚稀构函数(可以看到any对content调用了delete)
下面是holder的实现,holder是一个模板,里面定义的
ValueType held;
很明星是any用来保存任何类型的,回顾下上面所说的any初始化content的2种方法
(1)content(new holder<ValueType>(value))
(2)content(other.content ? other.content->clone() : 0)
从这个地方可以看到怎么初始化holder对象,并保存到content.注意到这里的held是public的,这样就提供了对数据访问的功能,在访问的时候必须要知道具体要访问的类型,才能调用相应的static_cast或者dynamic_cast来操作,而这样其实也提供了型别安全的保证,eg:不象malloc,返回void*,然后()转换一下。
5:看下怎么访问any里面的属性值:这里就不列举出所有的实现,因为有些是对const的版本。
template<typename ValueType>
ValueType * any_cast(any * operand)
{
    return operand && operand->type() == typeid(ValueType)
                    ? &static_cast<any::holder<ValueType> *>  (operand->content)->held
                    : 0;
}
 
template<typename ValueType>
ValueType any_cast(const any & operand)
{
     typedef BOOST_DEDUCED_TYPENAME        remove_reference<ValueType>::type nonref;
 
   const nonref * result = any_cast<nonref>(&operand);
   if(!result)
            boost::throw_exception(bad_any_cast());
    return *result;
}//这里去掉1些原来实现的代码和注释
可以看到具体的实现方式&dynamic_cast的逻辑差不多,对引用的cast有可能抛出异常。通过上面这种方式,就达到了对数据的读取,读取时必须知道里面的数据类型。可以看出any只能保存一个值,-_-''不向我那个,可以同时保存不同类型的值。
6:extension
可以通过std::vector<boost::any> anys,来构建一个任何类型的列表,但访问比较麻烦。
也可以通过any来达到虚函数不能为template的限制(因为一个是静态的一个是动态的)
象下面:
class CBase
{
 public:
     virtual void Set(boost::any) = 0;
};
 
class CHild:
     public CBase
{
 public:
     virtual void Set(boost::any param)
     {
          m_value = param;
     }
 private:
     boost::any  m_value;
};
 
CHild test;
CBase* ptr = &test;
ptr->Set(1);
ptr->Set('a');
7.finish...总算完成了...-_-''要变唐僧了...
                                                  alex. agerlis@163.com
posted on 2007-02-11 15:54 agerlis 阅读(411) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理