C模板22(基于traits的泛型程序设计)
熟悉STL的了解traits,特别是type-traits,提供了很多traits,称为元函数,可以基于某个类型计算出所需的类型。
Policy其实也是一种trait,只是后者强调类型,而前者重视行为。Andrei Alexandrescu,Modern C++ Design的作者认为:
policies和policy classes有助于我们设计出安全、有效率且具高度弹性的"设计元素",所谓policy,就是用来定义一个class 和class template的接口,该接口由下列之一或全部组成:内隐型别定义(inner type definition)、成员函数和成员变量。
下面通过一个简单的例子来说明一下:计算某个序列的和。template T accumulate(const T *begin, const T *end) { T sum{}; while (begin != end) { sum += *begin; ++begin; } return sum; }
上面代码很容易理解,不过其间也有几个隐式约束:序列必须是连续存放的,通过移动begin最终可以到达end,T类型可以通过缺省初始化为零值,其解引用的值能够使用+=运算。int num[] = {1, 2, 3, 4, 5}; accumulate(num, num + 5); // 15 char hello[] = "hello, world"; accumulate(hello, hello + sizeof(hello) - 1); // -120??
好像有点问题,哦,原因是char的数值范围太小了,作为返回值的类型在累加计算过程中它溢出了。解决方式可以应用traits,定义模板参数T的累加和返回值类型时的关联类型(元函数)。template struct accumulate_traits { using type = T; }; template <> struct accumulate_traits { using type = int; }; template <> struct accumulate_traits { using type = int; }; template using accumulate_traits_t = typename accumulate_traits::type; template accumulate_traits_t accumulate(const T *begin, const T *end) { accumulate_traits_t sum{}; while (begin != end) { sum += *begin; ++begin; } return sum; }
我们定义了一个trait(元函数)accumulate_traits,用来计算类型参数T的返回值类型:缺省返回T自己,对于size小于int的类型(如char, short)则返回int。我们还仿照C++14的做法,定义了acculate_traits_t,方便用户使用。int num[] = {1, 2, 3, 4, 5}; accumulate(num, num + 5); // 15 char hello[] = "hello, world"; accumulate(hello, hello + sizeof(hello) - 1); // 1160
这回运行一切正常。accumulate模板函数对付基本数值类型足够了,但是accumulate_traits_t sum{};
这里累加和sum变量的零值初始化的依赖有点让人担心(使用类型的缺省构造,且符合零值语义)。如果用于自定义类型,一不小心这里很容易挂掉。我们未雨绸缪,再添加一个policy,用来定义返回值类型的零值,这样将来如果需要支持的类型有特定的零值构建方式,可以使用特化技术来添加对此类型的支持。template struct accumulate_traits { using type = T; inline static constexpr type zero_value = 0; }; template <> struct accumulate_traits { using type = int; inline static constexpr int zero_value = 0; }; template <> struct accumulate_traits { using type = int; inline static constexpr int zero_value = 0; }; template using accumulate_traits_t = typename accumulate_traits::type; template accumulate_traits_t accumulate(const T *begin, const T *end) { accumulate_traits_t sum = accumulate_traits::zero_value; while (begin != end) { sum += *begin; ++begin; } return sum; }
如果有个自定义类型Foo,它定义了自己的返回值类型,还有特有的初始化方式,我们可以针对它添加特化template <> struct accumulate_traits { using type = typename Foo::ResultType; inline static constexpr Foo zero_value = Foo::Initialize(0); };
这种声明式的(通过添加定义)无缝、透明地功能扩展方式也是STL功能扩展的一种方式,一旦你理解了其间的运作方式,会大大提升你的编程效率。这里模板参数T的关联属性通过trait(返回值类型)或policy(零值的获取方式),可以非常方便地配置、扩展accumulate函数,使之适用于各种类型。比如说这里的+=累和算法,也可以通过定义一个policy来定制化,缺省内置数值类型我们使用+=运算符,对于自定义类型,可以使用特定的累加方式。
最后补充一点:上面traits的应用是固定的,你无法更换,我们可以将traits类型也参数化,这样在特定场合,你可以用其他的traits来替换它,只要你的traits也提供了同样的traits定义。template > auto accumulate(const T *begin, const T *end) { typename AT::type sum = AT::zero_value; while (begin != end) { sum += *begin; ++begin; } return sum; }
我们把traits类型定义为第二个模板参数,它有一个缺省值,就是我们之前定义好的traits类,通常你不需要关注它,除非你有特定的需求,需要替换缺省实现。看着是不是有点眼熟?是啊,STL的容器模板类里就有很多类似的应用。
你如何看待刘亦菲主演票房失控这件事?小编为什么整出这样的话题?有点不明白,是不是电影公司领导的脑袋被门给挤了?限韩的势头这么猛,为什么这时候去用热脸贴人家冷屁股?当下没人捧场算是幸运了,韩国人一直是亲美亲日,做人家走
可以说一说AG超玩会一诺的人生经历吗?说到一诺,对王者比赛稍微熟悉的朋友一定会想起kpl最强关羽四杀队友的饭后故事。在BA黑凤梨与YTG的一场比赛中,双方打团,眼看BA即将收割对方,一诺却将正在一技能挥砍阶段的吕布,顶
在玩我的世界的时候,你遇到过哪些奇葩的事?这里是专注于有为青年游戏体验的敢为青年游场,我是敢哥!在玩我的世界的时候,你遇到过哪些奇葩的事?我的世界作为一个沙盒游戏,还是很有意思的,但是也让很多人玩着感觉很懵逼,而我就是其中
背假包是一种什么心理?背假包的女孩都是怎么想的?这问题就提得不明确,什么叫假包?只要能装东西的都是货真价实的包。而题主想说的假包应该是指那些品牌包的高仿包或山寨包吧。所以权当那就是假包吧,要说什么心理,虚荣好玩实用划算,我想不同
上世纪日本房地产泡沫破裂,房价下跌为什么没有人买?都不缺房子吗?前几天刚从日本回来。感触挺深。有句话,我要分享给大家,就是历史不会重演,但是历史总是惊人的相似。日本有过的路,现在中国非常值得借鉴。战后的日本,就走向了一个靠房地产拉动经济的怪圈,
为什么国际足联认可的世界第一球王是贝利而不是马拉多纳呢?看完了你就会有答案。FIFA18加入的五位传奇巨星分别是两代巴西球王贝利和罗纳尔多,阿根廷传奇迭戈马拉多纳,前苏联门神列夫雅辛还有法国锋线杀手蒂埃里亨利。1,贝利98出生在巴西的一
80分贝的听力配上助听器效果会好吗?只要有残余听力,戴上助听器就会有效果,至于效果好不好,要看本身一个言语分辨率的情况,以及所选择助听器的档次。通常来讲听力下降的时间越短且病程不复杂的话,佩戴上助听器的效果应该还好,
OPPO折叠屏FindN有外观曝光了吗?长啥样?不得不说,近期关于OPPO首款折叠屏手机OPPOFindN的外观信息,确实引起很多小伙伴的关注。根据OPPO官微放出预热视频以及刘作虎发表的长文,我们还是可以从中获取到一些信息的。
年纪大了,面部都下垂了,有什么方法可以提拉一下?在保持体重在正常范围加强防晒保湿等基础上,需要激光肉毒素玻尿酸注射以及玻尿酸填充提升等医美手段联合规律治疗最简单的办法就是用塑料胶布机械性地往上拉,然后贴在头皮上(当然要剃光头)。
农村户口,社保和新农合选哪个更划算?感谢邀请,更感谢楼主的提问。楼主你好,农村户口社保和新农合应该选哪个更划算?社保和新农合还是有本质的区别的,当然不论你选择哪一种来参保,对于自己来讲,只能够选择其中的一种来参保,并
如果把大乐透的奖池掏空,能拿到钱吗?应该是可以的,只不过由于数额太过于庞大,有可能体彩中心会采用国外的一些办法,就是除去个人税务之后,分期付款的方式来付清奖金数额。目前,大乐透奖池内是六十亿元左右,除去20的个人偶然