手机站
网通分站
电信主站
密 码:
用户名:
当前位置 : 主页>程序设计>C/C++>列表

Bjarne:为什么不能为模板参数定义约束?

来源:互联网 作者:west263.com 时间:2008-02-23
西部数码-全国虚拟主机10强!40余项虚拟主机管理功能,全国领先!双线多线虚拟主机南北访问畅通无阻!免费赠送企业邮局,.CN域名,自助建站480元起,免费试用7天,满意再付款! P4主机租用799元/月.月付免压金!
  能够的,而且方法很简单和通用。

  看看这个:

template<class Container>
void draw_all(Container& c)
{
 for_each(c.begin(),c.end(),mem_fun(&Shape::draw));
}

  假如出现类型错误,可能是发生在相当复杂的for_each()调用时。例如,假如容器的元素类型是int,我们将得到一个和for_each()相关的含义模糊的错误(因为不能够对对一个int值调用Shape::draw的方法)。

  为了提前捕获这个错误,我这样写:

template<class Container>
void draw_all(Container& c)
{
 Shape* p = c.front(); // accept only containers of Shape*s
 for_each(c.begin(),c.end(),mem_fun(&Shape::draw));
}

  对于现在的大多数编译器,中间变量p的初始化将会触发一个易于了解的错误。这个窍门在很多语言中都是通用的,而且在任何的标准创建中都必须这样做。在成品的代码中,我也许能够这样写:

template<class Container>

void draw_all(Container& c)
{
 typedef typename Container::value_type T;
 Can_copy<T,Shape*>(); // accept containers of only Shape*s
 for_each(c.begin(),c.end(),mem_fun(&Shape::draw));
}

  这样就很清楚了,我在建立一个断言(assertion)。Can_copy模板能够这样定义:

template<class T1, class T2> struct Can_copy {
 static void constraints(T1 a, T2 b) { T2 c = a; b = a; }
 Can_copy() { void(*p)(T1,T2) = constraints; }
};

  Can_copy(在运行时)检查T1是否能够被赋值给T2。Can_copy<T,Shape*>检查T是否是Shape*类型,或是个指向由Shape类公共继承而来的类的对象的指针,或是被用户转换到Shape*类型的某个类型。注意这个定义被精简到了最小:

  一行命名要检查的约束,和要检查的类型

  一行列出指定的要检查的约束(constraints()函数)

  一行提供触发检查的方法(通过构造函数)

  注意这个定义有相当合理的性质:

  您能够表达一个约束,而不用声明或复制变量,因此约束的编写者能够用不着去设想变量如何被初始化,对象是否能够被复制,被销毁,连同诸如此类的事情。(当然,约束要检查这些属性的情况时例外。)

  使用现在的编译器,无需为约束产生代码

  定义和使用约束,无需使用宏

  当约束失败时,编译器会给出可接受的错误信息,包括“constraints”这个词(给用户一个线索),约束的名字,连同导致约束失败的周详错误(例如“无法用double*初始化Shape*”)。

  那么,在C 语言中,有没有类似于Can_copy——或更好——的东西呢?在《C 语言的设计和演变》中,对于在C 中实现这种通用约束的困难进行了分析。从那以来,出现了很多方法,来让约束类变得更加容易编写,同时仍然能触发良好的错误信息。例如,我信任我在Can_copy中使用的函数指针的方式,他源自Alex Stepanov和Jeremy Siek。我并不认为Can_copy()已能够标准化了——他需要更多的使用。同样,在C 社区中,各种不同的约束方式被使用;到底是哪一种约束模板在广泛的使用中被证实是最有效的,还没有达成一致的意见。

  但是,这种方式很普遍,比语言提供的专门用于约束检查的机制更加普遍。无论如何,当我们编写一个模板时,我们拥有了C 提供的最丰富的表达力量。看看这个:

template<class T, class B> struct Derived_from {
 static void constraints(T* p) { B* pb = p; }
 Derived_from() { void(*p)(T*) = constraints; }
};

template<class T1, class T2> struct Can_copy {
 static void constraints(T1 a, T2 b) { T2 c = a; b = a; }
 Can_copy() { void(*p)(T1,T2) = constraints; }
};

template<class T1, class T2 = T1> struct Can_compare {
 static void constraints(T1 a, T2 b) { a==b; a!=b; a<b; }
 Can_compare() { void(*p)(T1,T2) = constraints; }
};

template<class T1, class T2, class T3 = T1> struct Can_multiply {
 static void constraints(T1 a, T2 b, T3 c) { c = a*b; }
 Can_multiply() { void(*p)(T1,T2,T3) = constraints; }
};

struct B { };
struct D : B { };
struct DD : D { };
struct X { };

int main()
{
 Derived_from<D,B>();
 Derived_from<DD,B>();
 Derived_from<X,B>();
 Derived_from<int,B>();
 Derived_from<X,int>();

 Can_compare<int,float>();
 Can_compare<X,B>();
 Can_multiply<int,float>();
 Can_multiply<int,float,double>();
 Can_multiply<B,X>();
 Can_copy<D*,B*>();
 Can_copy<D,B*>();
 Can_copy<int,B*>();
}

// 典型的“元素必须继承自Mybase*”约束:

template<class T> class Container : Derived_from<T,Mybase> {

// ...

};

  事实上,Derived_from并不检查来源(derivation),而仅仅检查转换(conversion),但是这往往是个更好的约束。为约束想一个好名字是很难的。


文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

热点关注
IDC资讯 虚拟主机 域名注册 托管租用 vps主机 智能建站
网站运营 建站经验 策划盈利 搜索优化 网站推广 免费资源
网站联盟 联盟新闻 联盟介绍 联盟点评 网赚技巧
行业资讯 业界动态 搜索引擎 网络游戏 门户动态 电子商务 广告传媒
网络编程 Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术 Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷 Internet Explorer
网页制作 FrontPages Dreamweaver Javascript css photoshop fireworks Flash
程序设计 Java技术 C/C++ VB delphi
网络知识 网络协议 网络安全 网络管理 组网方案 Cisco技术
操作系统 Win2000 WinXP Win2003 Mac OS Linux FreeBSD
返回首页 |关于我们 | 联系我们 | 付款方式 | 创业联盟 | 价格总览 | 资讯中心 | 友情链接 | 网站地图 | 招贤纳士 | RSS