tommy

It's hard to tell the world we live in is either a reality or a dream
posts - 52, comments - 17, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理
就是这样一个类:
template <class T,class U>
class Conversion
{
    typedef 
char Small;
    
class Big char dummy[2]; };
    
static Small Test(U);
    
static Big Test();
    
static T MakeT();
public:
    
enum { exists = sizeof(Test(MakeT())) == sizeof(Small) };
}
;

关于函数 Small Test(U) 和 Big Test(...) ,书里面说:
。。。需要两个重载函数,其一如先前所说,接受一个U对象并传回一个Small对象:
Small Test(U);
但接下来,我该如何写出一个可接受任何其他种对象的函数呢?。。。。

我觉得这个地方翻译得有点问题,是不是应该说:“。。我该如何写出一个可接受任何另外一种类型(即 T)的对象的函数呢。。”,因为这里就是 T和U嘛, 没有什么“其他种”,这样翻译容易让我迷惑不解了一会儿。

如果接受 U的那个函数被调用,则T可以被转换为 U,否则无法转换,这个是思路的根本。

为什么要做一个 MakeT这样的函数而不直接使用T呢? 这是为了满足当 T 只有私有构造函数的情况,对于编译器来说,sizeof 是在编译期完成评估的,所以,MakeT 里面到底做了什么并不重要,重要的是他返回的类型,是 T,所以,作者很兴奋地说,这是一个 StrawMan function,即“稻草人函数”,哈哈,只是一个样子而已,但是这已经足够了,那两个重载的Test方法也是一样,这里我们不关心他的函数体。强啊,爽歪歪,快感的源泉啊

测试代码如下:
    using namespace std;

    cout 
<< Conversion<doubleint>::exists << ' '
        
<< Conversion<charchar*>::exists << ' '
        
<< Conversion<size_t, vector<int> >::exists << ' ';
输出: 1 0 0
double可以转换为 int
char 不能转换为 char*
vector<int> 是一个容器的构造函数,size_t 不能转换,因为这个构造函数是 explicit的,这个地方还是有点迷糊,还得研究一下。

Feedback

# re: 读书笔记《C++设计新思维》(5) 编译期间侦测可转换性  回复  更多评论   

2006-10-10 15:37 by wanglile
exists = sizeof(Test(MakeT())) == sizeof(Small)
这句,是不是说Test(...)这种函数的优先级是低于类型转换,所以如果T可以转换为U类型那Test(...)就变成调用Test(U),于是exists就是true,说明T和可以相互转换。

# re: 读书笔记《C++设计新思维》(5) 编译期间侦测可转换性  回复  更多评论   

2006-10-11 05:22 by tommy
这是编译时逻辑,不是运行时逻辑。
enum { exists = sizeof(Test(MakeT())) == sizeof(Small) };
编译器根据程序中的代码调用状况,决定应该如何编译template相关的代码,
在编译时刻Conversion<T, U>::exists的值就计算出来了,
首先,sizeof(Small) 等于 1,
如果T就是U,或者T可以转换成U类型(这个就是关键),那么 Test(T) 就是Test(U),sizeof就等于sizeof(Small),恒等,意思是

Conversion<T,T>::exists一定是true,类型总是可以转换成自己。
如果T不是U,并且T不能转换成U类型,那么static Big Test(...)会被编译器“调用”(权且用这个词,编译原理只学了半桶水,不能装懂)

,因而exists就是false了(sizeof(Big)!=sizeof(Small),因为2!=1)。
之所以用MakeT这个函数,如作者所说,是为了满足当 T 只有私有构造函数的情况,编译器会在编译时检查语言的封装逻辑是否被违反,如果

存在违反情况将出现编译错误,MakeT这个函数就是为了绕过这个检查而设的,
我的理解是:用于运行时的代码中也没有“调用”这个函数,因而MakeT没有函数体也不会引起连接错误,就是编译通过了。

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