今天看FireBreath框架时,发现里面有个variant_list_of的函数,这个函数的作用有些独特,可以保存任意个函数参数,看下面的代码:
1 2
| VariantList var = variant_list_of(1)(2)(3); VariantList var = variant_list_of(1);
|
就是说需要多少个元素只需要在variant_list_of函数后面添加多少个()即可。
觉得这个函数非常有趣,有些像C语言中的可变参数函数,于是看了一下FireBreath的源码中的实现。
后来发现FireBreath是通过重载()运算符实现这个功能的
variant_list_of函数定义如下:
1 2 3 4 5
| inline FB::detail::VariantListInserter variant_list_of(FB::variant v) { return FB::detail::VariantListInserter(v); }
|
可见它是返回一个VariantListInserter对象。而对象class定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class VariantListInserter { public: VariantListInserter() : m_l() {} VariantListInserter(FB::variant v) : m_l(1, v) {} VariantListInserter& operator()(FB::variant v) { m_l.insert(m_l.end(), v); return *this; } operator FB::VariantList& () { return m_l; } operator FB::variant() { return FB::variant(m_l); } private: FB::VariantList m_l; };
|
很简单的一个辅助类,唯一成员就是VariantList, VariantList在源码就是一个vector<variant>
从上述代码很容易看出是如何实现的,以下这句代码为例子说明
1
| VariantList var = variant_list_of(1)(2)(3);
|
- 首先执行variant_list_of,该函数以(1)为函数参数,返回一个VariantInserter类
- 经过step1后,此时上面的代码变成VariantListInsterter(2)(3),由于重载了()运算符,那么就会依次调用()运算符,从(2)到(3)
- 经过两次的()运算符调用后,因此等式右边类型仍然为VariantListInserter,但是该类重载了类型转换操作符(代码:operator FB::VariantList& ()),这时赋值前就会把类型转换层VariantList后再赋值给var.
不得不感叹其中巧妙之处:利用()运算符,在调用1次()后返回自身再依次调用后面的(),连锁下去。这样就可以保存任意参数。
下面是上述的简化版代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class VaraintList { public: VaraintList(int a) { var_list.push_back(a); } VaraintList& operator() (int a) { var_list.push_back(a); return *this; } operator vector<int>& () { return var_list; } private: vector<int> var_list; }; VaraintList varaint_list_of(int a) { return VaraintList(a); }
|