C++11新特性(71)-可变参数模板的参数转发

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/craftsman1970/article/details/82594888

本次内容不多,但是不大好理解。本文通过一个稍微复杂但是很实用的例子进行说明。本文是可变参数模板的最后一篇,同时也是可变参数模板的综合练习。

实例

很多软件系统都存在日志(log)功能,通过日志信息可以确认系统的状态和动作的过程。日志大多是文本形式的。虽然很方便,但是碍于文本形式本身的局限性,存储过程中会发生信息的丢失。

本文实现一个可以保存多种信息的信息存储类。

Segment是一个抽象类,定义了信息片段的基本形态,代码如下:

由于只是一个雏形,目前只是定义了一个output操作并重载了输出运算符。目的是为了以文本形式输出信息的内容。

接下来是两个派生类,分别用于存储整数信息和字符串信息。

IntSegment类的内容很简单,这里省略说明。

StringSegment类需要注意的是:构造函数有两个版本,分别对应左值引用参数和右值引用参数。当参数类型为左值引用时,m_msg成员执行拷贝构造函数;当参数类型为右值引用时,m_msg成员执行移动构造函数。

最后是MsgHolder类。

MsgHolder类使用一个vector来保存信息片段,使用output配合输出运算符输出文本形式的信息。

MsgHolder还另外提供了三个add函数模板,前两个固定参数的add方法用于创建IntSegment和StringSegment对象,可变参数的方法用于接受不特定多数的参数并转发。

可变参数模板参数转发

和固定参数模板函数同样,可变参数模板同样会发生引用合并,所以在模板参数传递的过程中,也使用了std::forward。其用法如下:

add(std::forward<Args>(rest)...);

MsgHolder用法示例

上述准备工作完成后,就可以使用它们了。示例代码如下:

在add方法中,分别投入了整数,字符串常量,左值引用和右值引用。对于每一种情况都产生了正确的输出;在右值引用的场合也发生了移动操作。

也就是说,使用者希望继续使用字符串时(ltest的情况),就正常传递该参数,这时存储字符串的拷贝;使用者明确不再需要某个字符串时(rtest的情况),使用std::move通知给编译器,这时存储的就是字符串本身而不会发生拷贝动作。

如果没有正确使用std::forward的话,右值引用的部分就无法正常动作。无论哪种情况都会发生字符串拷贝。

关于扩展信息存储类的扩展

目前的MsgHolder还只是一个雏形,您可以增加Segment的派生类以扩展支持的数据类型;也可以增加输出方法以提供其他形式的输出。

一家之言

由于引用合并的存在,模板参数的右值引用(允许移动操作)信息经常会丢失,这时就需要使用std::forward将其恢复。

参考资料

C++11新特性(67)- 标准库forward函数

C++11新特性(65)- 引用合并

C++11新特性(68)- 可变参数模板(variadic template)

示例代码:https://github.com/xueweiguo/OOThinking/blob/master/20180429%20forwardPacket.cpp

觉得本文有帮助?请分享给更多人。

阅读更多更新文章,请扫描下面二维码,关注微信公众号【面向对象思考】

猜你喜欢

转载自blog.csdn.net/craftsman1970/article/details/82594888