51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

spdlog中的完美转发

spdlog是一个c++实现的日志库,代码中大量使用了c++11的特性,并且只需要头文件就可以使用,十分值得使用和研究。

下面这段代码是spdlog中的一个工厂函数,用来创建一个新的logger,里面用到了c++11之后才支持的完美转发。

|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 | template<typename Sink, typename... SinkArgs> static std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&... args) { auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...); auto new_logger = std::make_shared<spdlog::logger>(std::move(logger_name), std::move(sink)); details::registry::instance().initialize_logger(new_logger); return new_logger; } |

SinkArgs这个可变长度的模板参数是完美转发的目标,定义成&&,右值引用。std::make_shared会在构造Sink对象时将SinkArgs传递给Sink的构造函数,SinkArgs需要使用std::forward传递,这样就能将参数原原本本的传递给Sink的构造函数,当Sink有不同的构造函数时还能自动匹配。

我们来写代码验证一下。

首先写一个有多种构造函数的类Data,每个构造函数里都不干啥,只是打印一条信息。

|------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class Data { public: Data() { printf("Data()\n"); } Data(int a) { printf("Data(int a)\n"); } Data(int a, float b) { printf("Data(int a, float b)\n"); } ~Data() { printf("~Data()\n"); } }; |

然后我们为Data写一个工厂函数,像下面这个样子,也比较简单,只是创建一个指针再返回出来。

|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 | template <typename T, typename ...Args> std::shared_ptr<T> CreateData(Args &&...args) { return std::make_shared<T>(std::forward<Args>(args)...); } |

测试代码如下。

|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 | int main(int argc, const char *argv[]) { auto a = CreateData<Data>(); auto b = CreateData<Data>(1); auto c = CreateData<Data>(1,1.5); return 0; } |

运行之后输出如下,就和预想的一样。

|---------------------|-------------------------------------------------------------------------| | 1 2 3 4 5 6 | Data() Data(int a) Data(int a, float b) ~Data() ~Data() ~Data() |

大家可能注意到,CreateData返回的并不是裸指针,而是make_shared出来的shared_ptr,下面是make_shared的代码,有没有觉得很眼熟呢?

|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 | template<typename _Tp, typename... _Args> inline shared_ptr<_Tp> make_shared(_Args&&... __args) { typedef typename std::remove_const<_Tp>::type _Tp_nc; return std::allocate_shared<_Tp>(std::allocator<_Tp_nc>(), std::forward<_Args>(__args)...); } |

没错,make_shared在为shared_ptr构建对象时也用到了完美转发,如果我们再给Data包装一个具有引用计数功能的管理类,就很像是shared_ptr的实现了。

参考链接:https://zhuanlan.zhihu.com/p/275075782


赞(3)
未经允许不得转载:工具盒子 » spdlog中的完美转发