std::tuple
是 C++11 中的一个好东西. 它功能上算是std::pair
的扩展,
但有一些其他的用法.
例如, 可以借用 tuple 来模拟多值返回 (Python 中也是这样),
SugarCpp
中就是使用 tuple 实现了简洁的多值返回语法:
tuple 也可以用于模拟 Python 中的 Parallel Assignment:
对于接受 tuple 做参数的函数, 想要原地创建一个 tuple 传进去应该怎么办呢?
使用std::make_tuple
显然会增加一次复制开销.
这时候可以使用forward_as_tuple
:
但是反过来呢? 对于一个接受一列参数的函数, 怎样将一个已存在的 tuple 传进去?
我们肯定期待 Python 的 argument unpacking 写法:
而不希望看到这样:
C++ 中显然没法像 Python 那么 elegant, 但是我发现有人用模板实现了类似的事情, 称为 Tuple Explode.
它大概长成这个样子:
K 是一个 counter, 用来数当前扩展到第几个参数, 调用时赋为参数个数. RET 是函数 func 的返回值类型,
F 是函数类型.
看看expand
函数做了什么: 首先, 传入的 func, t, ...args 都是 universal reference, 因此递归时用std::forward
保持其型别不变.
同时, 从 tuple 中取出第 K 个元素, 插入到参数列表args...
的首部, 随后 K 减 1.
因此递归结束时的 specialization 里, 我们应该调用我们要的函数了:
其中forward<T>...
将对每个参数都做 forward.
有了 Expander 的定义, 我们已经能通过如下代码实现传参了:
当然, 我们还想让世界更简单一点, 所以再写一个模板函数:
其中用sizeof...
运算符取出 tuple 模板参数个数.
用std::result_of
获得 func 的返回值类型.
ps: C++11 的result_of
实现方式如下:
有了这样定义的explode
函数之后, 就可以方便的实现 tuple 传参了..:
另外, 我们的explode
支持的类型还不够完整..
加上 const reference 和 rvalue reference, 以便在其他地方使用:
不得不感慨..C++11 出来之后, 那些能折腾模板的人折腾完 boost 又有事干了..