posts - 18,  comments - 104,  trackbacks - 0

关于boost::any,今天心血来潮,顺手实现了一个。不想加有关type_info的东西,所以自我创造了一个用dynamic_cast的版本,仅供学习。
要用当然要boost::any的嘛。

关于模板,首先说两条:

1. 类模板
   (缺点)类模板不能自动推导模板参数(意思是当要用到某个模板类,比如A,那么你使用的时候一定要有模板参数,比如A<int>,编译器不能自动推导),只能通过特化模板而是编译器选择合适的特化版本,
   (优点)类模板可以通过类模板把推导后的模板参数输出,通常使用 typedef _Type value; 。

2. 函数模板
   (优点)函数模板可以自动推导模板参数(意思是你顶一个模板函数,比如f,那么使用的时候不一定要有模板参数,比如f(123),编译器会自动推导123为int),当然这里可以靠函数重载和编译器匹配顺序,来决定很多事情。
   (缺点)函数模板不能输出推导后的类型。
 1 struct any
 2 {
 3     struct content
 4     {};
 5 
 6     template<typename _U>
 7     struct impl : public content
 8     {
 9         _U _u;
10 
11         impl(const _U& u)
12             : _u(u)
13         {}
14 
15         typedef _U type;    
16     };
17 
18     template<typename _U>
19     any(const _U& c)
20         : _t(new impl<_U>(c))
21     {}
22 
23     content* _t;
24 };

那么要实现any,any本身不是类模板,所以要接受任何参数,那么其构造函数必须是函数模板,但是函数模板不能导出推导后的类型,那么需要靠类模板来保存类型信息。


1 struct any
2 {
3     template<typename _U>
4     any(const _U& c)
5     {}
6 };

可以看出,上面的any定义可以接受任何类型的参数,比如 any t1(1); any t2(1.0); 注意1和1.0不一样。 但是输入的东西没有保存起来,起不到一个任意类型变量的作用(就是个空壳)。所以继续修改,

 1 struct any
 2 {
 3 
 4     template<typename _U>
 5     struct impl
 6     {
 7         _U _u;
 8 
 9         impl(const _U& u)
10             : _u(u)
11         {}
12 
13         typedef _U type;    
14     };
15 
16     template<typename _U>
17     any(const _U& c)
18         : _t(new impl<_U>(c))
19     {}
20 
21     impl<???>* _t;
22 };

前面说过,类模板可以保存类型信息,所以加入了一个 impl 的类模板,通过any的构造函数推导出的类型,将参数的类型保存在impl里面。看到最后一样的问号了吧,哪里要写什么呢?
any其实不知道他自己里面是什么东西呀,所以为了让any知道,定义一个类A,然后让impl继承它,那么这个A就是所有impl<>的父类了,不管impl里面是什么,都是一个A。当然起名A不好听,换个吧。

 1 #include <typeinfo>
 2 
 3 using namespace std;
 4 
 5 struct any
 6 {
 7     struct content
 8     {
 9         virtual ~content() {};
10     };
11 
12     template<typename _U>
13     struct impl : public content
14     {
15         _U _u;
16 
17         impl(const _U& u)
18             : _u(u)
19         {}
20 
21         typedef _U type;    
22     };
23 
24     template<typename _U>
25     any(const _U& c)
26         : _pc(new impl<_U>(c))
27     {}
28 
29     ~any()
30     {
31         delete _pc;
32     }
33 
34     template<typename _T>
35     _T& get()
36     {
37         impl<_T>* p = dynamic_cast<impl<_T>*>(_pc);
38         if(0 == p)
39             throw bad_cast();
40         return p->_u;
41     }
42 
43 private:
44     content* _pc;
45 };
46 
47 void main()
48 {
49     any a(10);
50     any b(1.0);
51     int x = a.get<int>();
52     double y = b.get<double>();
53 }


现在可以看到, content代替了那个不知道些什么类型的???,这个技术名字叫类型消除技术,在boost里面用的很多,也算是一个经典的技术了。

posted on 2009-02-20 14:27 尹东斐 阅读(2244) 评论(8)  编辑 收藏 引用

FeedBack:
# re: boost::any 为什么要用 static_cast 呢?
2009-02-20 17:33 | 尹东斐
@lwan

这里还是要动静结合的,所有cast都是运行期做的事情。在编译期,能用的运算型关键字少得可怜,像 sizeof 这种。所以有必要的时候,可以借助运行期的特性。

静态还是为动态服务的,不必在他们之间画出一条道来,从此不往来。只要能尽可能的解决问题,并优雅,高效就是王道。  回复  更多评论
  
# re: boost::any 为什么要用 static_cast 呢?
2009-02-20 21:50 | 发生地方
领教了  回复  更多评论
  
# re: boost::any 为什么要用 static_cast 呢?
2009-02-20 22:01 | ebenzhang
static_cast 不用RTTI
dynamic_cast才用RTTI.  回复  更多评论
  
# re: boost::any 为什么要用 static_cast 呢?
2009-02-20 22:36 | 尹东斐
@ebenzhang

boost::any的实现中,用type_info配合static来做类型检查。
所以我说他用RTTI。

我意思是不想通过使用 typeid 获得 type_info,从而检查类型。

我没有说清楚,谢谢提醒。  回复  更多评论
  
# re: boost::any 为什么要用 static_cast + type_info 呢?
2009-02-25 23:11 | 童承斌
阿飞,顶你哈,写的真不错,我要多来逛逛  回复  更多评论
  
# re: boost::any 为什么要用 static_cast + type_info 呢?
2009-02-25 23:30 | yindf
@童承斌


你也来踩啦,多谢多谢。
你的地址呢,我也去看看,现在每天都贼无聊,就写写blog,游戏都不玩了。  回复  更多评论
  
# re: boost::any 为什么要用 static_cast + type_info 呢?
2009-04-10 11:07 | 蚂蚁终结者
不错,谢谢分享!  回复  更多评论
  
# re: boost::any 为什么要用 static_cast + type_info 呢?
2010-01-07 09:35 | max_man
类型消除很容易做到,可是反过来做类型识别就不那么容易了。
比如如果外部事先不知道any里面的数据类型,要正确的把里面的数据取出来就麻烦多了。  回复  更多评论
  

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


<2009年2月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
1234567

常用链接

留言簿(4)

随笔档案

文章分类

文章档案

相册

好友博客

搜索

  •  

最新评论

阅读排行榜

评论排行榜