用C++11实现C++14的std::get,并且增加默认值功能

需求:

tupel 的 std::get<TYPE> 如果取了不存在的类型就返回一个默认的

首先来看get的实现:

这一段不用多解释,变参模板递归展开,用枚举value的值来指明C++11中std::get<N>的N值,此时get非tuple包含类型会编译错误,这是合理的,现在就要动点手脚让它满足需求

为了满足需求,对get的改动如下(感谢社区mogu提供的方法):

在参数末尾构造了一个T的临时对象,每次get的时候会预先把这个T对象添加到临时创建的一个新tuple里面,很巧妙的,如果是原tuple内的类型会正确返回,如果不是就会匹配到新添加进去的这个从而返回。

不过,需要注意的是新添加进去的这个仅仅是临时对象,它只能保证编译通过,返回的默认类型对象依然析构,所以不要尝试去使用它,当然如果传了生命期足够参数进去就没有问题。

从一个例子看现代C++的威力

引子

最近准备重构一下我的kapok库,让meta函数可以返回元素为kv的tuple,例如:

 

类似这个META的实现我在msgpack的库里看到了,在这里

msgpack中仅仅是宏元的代码就数百行了,看起来非常复杂,msgpack之所以用这么复杂的方式去实现恐怕是为了支持c++98/03标准。本来想看看msgpack是如何实现META函数的,但是它的宏元代码读起来比较困难,要读懂估计要花一天的时间,于是作罢。

后来想起群里的ddrm实现了类似的功能,据说没有msgpack这么复杂,简洁一些,于是向ddrm要来了代码(在此对ddrm分享的源码表示感谢)。他的思路也是用宏元,但是比msgpack的代码少很多,将近一百行代码。我不太喜欢这么复杂的代码,我希望用一种更简单的方式去实现这个效果。附上ddrm的代码,大家可以借鉴参考一下。

10行代码解决问题

我探索了一些可能的方案后,最终找到了一种满意的方案,最终的实现代码不过十来行,非常简洁,感谢c++11/14,正是现代C++才让代码变得如此简洁。

实现思路也比较简单,问题的本质是将输入的参数值变成一个pair,key是值的字面量,value是变量本身的值,所以生成的pair是这样的std::pair<std::string, someval>, 另外这个pair是每一个输入参数值都会生成一个pair,如果是一系列的参数值就要生成一系列的pair,这就要求支持变参。所以问题的关键是要在展开变参的过程中将这些pair放到一个tuple中,这对于c++11/14来说是不难办到的,下面是实现代码:

使用现代C++之后,仅仅需要10行代码就可以实现之前需要上百行甚至数百行代码才能实现的目标,这无疑体现了现代C++的巨大威力。除了非常简洁的优点之外,还解决了一个宏元无法彻底解决的问题,宏元需要预先定义一些参数的宏,这些宏定义是有限的,如果参数超出定义的上限就会编译报错,而这个变参版本完全不用担心这个问题,支持任意个参数。

后记

这件事给了我一个启示,如果我们一直按照前人的路去走,就很难超越前人,如果我们运用新的技术,改变思路,常常会化繁为简,化腐朽为神奇。只有通过新技术、新思维去创造、创新才能超越前人。

UPDATE

 

Copy Protected by Chetan's WP-Copyprotect.