为什么不能为模板参数定义约束计划
可以的,而且方法非常简单和通用。
看看这个:
templateclass Container
void draw_all(Container c)
{
for_each(gin(),d(),mem_fun(Shape::draw));
}
如果出现类型错误,可能是发生在相当复杂的for_each()调用时。例如,如果容器的元素类型是int,我们将得到一个和for_each()相关的含义模糊的错误(因为不能够对对一个int值调用Shape::draw的方法)。
为了提前捕捉这个错误,我这样写:
templateclass Container
void draw_all(Container c)
{
Shape* p = ont(); // accept only containers of Shape*s
for_each(gin(),d(),mem_fun(Shape::draw));
}
对于现在的大多数编译器,中间变量p的初始化将会触发一个易于了解的错误。这个窍门在很多语言中都是通用的,而且在所有的标准创建中都必须这样做。在成品的代码中,我也许可以这样写:
templateclass Container
void draw_all(Container c)
{
typedef typename Container::value_type T;
Can_copyT,Shape*(); // accept containers of only Shape*s
for_each(gin(),d(),mem_fun(Shape::draw));
}
这样就很清楚了,我在建立一个断言(assertion)。Can_copy模板可以这样定义:
templateclass 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_copyT,Shape*检查T是否是Shape*类型,或者是一个指向由Shape类公共继承而来的类的对象的指针,或者是被用户转换到Shape*类型的某个类型。注意这个定义被精简到了最小:
一行命名要检查的约束,和要检查的类型
一行列出指定的要检查的约束(constraints()函数)
一行提供触发检查的方法(通过构造函数)
注意这个定义有相当合理的性质:
你可以表达一个约束,而不用声明或复制变量,因此约束的编写者可以用不着去设想变量如何被初始化,对象是否能够被复制,被销毁,以及诸如此类的事情。(当然,约束要检查这些属性的情况时例外。)
使用现在的编译器,不需要为约束产生代码
定义和使用约束,不需要使用宏
当约束失败时,编译器会给出可接受的错误信息,包括“constraints”这个词(给用户一个线索),约束的名字,以及导致约束失败的详细错误(例如“无法用double*初始化Shape*”)。
那么,在C++语言中,有没有类似于Can_copy——或者更好——的东西呢?在《C++语言的设计和演变》中,对于在C++中实现这种通用约束的困难进行了分析。从那以来,出现了很多方法,来让约束类变得更加容易编写,同时仍然能触发良好的错误信息。例如,我信任我在Can_copy中使用的函数指针的方式,它源自Alex Stepanov和Jeremy Siek。我并不认为Can_copy()已经可以标准化了——它需要更多的使用。同样,在C++社区中,各种不同的约束方式被使用;到底是哪一种约束模板在广泛的使用中被证明是最有效的,还没有达成一致的意见。
但是,这种方式非常普遍,比语言提供的专门用于约束检查的机制更加普遍。无论如何,当我们编写一个模板时,我们拥有了C++提供的最丰富的表达力量。看看这个:
templateclass T, class B struct Derived_from {
static void constraints(T* p) { B* pb = p; }
Derived_from() { void(*p)(T*) = constraints; }
};
templateclass 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; }
};
templateclass T1, class T2 = T1 struct Can_compare {
static void constraints(T1 a, T2 b) { a==b; a!=b; ab; }
Can_compare() { void(*p)(T1,T2) = constraints; }
};
templateclass 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_fromD,B();
Derived_fromDD,B();
Derived_fromX,B();
Derived_fromint,B();
Derived_fromX,int();
Can_compareint,float();
Can_compareX,B();
Can_multiplyint,float();
Can_multiplyint,float,double();
Can_multiplyB,X();
Can_copyD*,B*();
Can_copyD,B*();
Can_copyint,B*();
}
// 典型的“元素必须继承自Mybase*”约束:
templateclass T class Container : Derived_fromT,Mybase {
// ...
};
事实上,Derived_from并不检查来源(derivation),而仅仅检查转换(conversion),不过这往往是一个更好的约束。为约束想一个好名字是很难的。查看本文来源
成都治疗白癜风好方法太原皮肤病
南京治妇科哪家医院好
- 微软大受欢迎《壮志凌云 2:独行侠》联名款 Xbox Series S 主机
- 设老年群体专场+送苗进社区 原以泾街道频出实招推进疫苗接种
- 容易被忽略的五位神仙,却是取经顺利的最大保障,他们是谁?
- 立秋了,这4浓汤适合“贴秋膘”,营养足口味好不长肉,舒服入秋
- 爱尔兰博主brittanybathgate基础单品搭 158cm矮个子女生的穿搭技巧
- 台球世锦赛:奥沙利文13-5淘汰马奎尔,第13次杀进世锦赛四强
- 《重生之门》正在热播,王俊凯张译二搭乘的《万里归途》又低调开机
- 爱吃粉条,认准这5种买准没错,质量好,廉价,不会买到假货
- 内蒙古下半年冷空气来袭!呼和浩特的天气是这样的……
- 奥诺哈:看过曼联本赛季比赛的人都知道,他们永远不会放弃
- 电视主持王冰冰遭人肉,网友称其在一起还离过婚,Twitter拿王思聪反驳
- 多少人败在辞职被领导算计上,这3句话剥肚里也别说,否则必吃亏