如何写一个函数的包装器(C++实现)(比如,可以计算函数执行的时间)

python中大量使用函数包装器。用C++也能用简洁的方式实现这个功能。可以把这个包装器实现成一个函数。

我们把实现包装器功能的这个函数命名为TimeMonitorFunc。下面先进行概述,然后介绍一下具体实现,最后介绍把这个包装器修改成一个简化的版本(注意,不是优化而是简化,功能也减少了)。

概述:

(1)功能:

任何一个可调用对象(例如函数)都能和TimeMonitorFunc结合在一起使用。这个包装器的功能是执行任意一个可调用对象并得出执行时间。

(2)原型:

template <typename T,typename... Args>
auto TimeMonitorFunc(long long& time, T&& func, Args&&... params)

(3)描述:

第一个参数time是一个传出参数,表示函数执行了多少毫秒。把可调用对象传给形参func,把可调用对象的参数在func后依次传入,TimeMonitorFunc的返回值即func的返回值。

下面介绍具体实现:

#include "pch.h"
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
using namespace std;
using namespace std::chrono;

std::string ToString(int a, int b, char c)
{
	this_thread::sleep_for(seconds(1));
	return to_string(a) + to_string(b) + c;
}

int ToInt(string str)
{
	this_thread::sleep_for(seconds(1));
	return atoi(str.c_str());
}

template <typename T,typename... Args>
auto TimeMonitorFunc(long long& time, T&& func, Args&&... params)
{
	long long  start_timestamp = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
	auto&& ret = forward<decltype(func)>(func)(forward<decltype(params)>(params)...);
	long long end_timestamp = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
	time = end_timestamp - start_timestamp;
	return ret;
}


int main()
{
	long long run_duration;
	string s = TimeMonitorFunc(run_duration, ToString,10, 20, 'a');
	cout << s << " " << run_duration <<endl;
	int number = TimeMonitorFunc(run_duration, ToInt,"555");
	cout << number << " " << run_duration << endl;
	getchar();
}

TimeMonitorFunc的参数列表和语句:auto&& ret = forward<decltype(func)>(func)(forward<decltype(params)>(params)...);涉及了多个C++11的名词,简单罗列这些名词,比如模板参数包、完美转发、万能引用,这种名词堆砌不友好。可以谈一下这两行代码做了什么。我的介绍不能完备的解释这些技术,只是开了个头。

参数列表中的T&& func和 Args&&... params相比普通的模板形参声明多了一个&&的修饰,这用来把形参声明成万能引用形参,效果是如果传入的实参是右值,那么模板函数实例化后形参变量的类型是右值,反之是左值。

函数体内使用了forward<decltype(func)>(func)和 forward<decltype(params)>(params)...这种用法也和右值有关。即使函数的形参变量是右值类型,在函数中使用这些形参变量时,它还是左值,因为对函数来说,这个形参变量就是一个局部变量;把函数形参变量声明成右值类型只是向编译器声明这个函数只接受右值类型的实参。forward的作用是:如果形参变量声明成右值类型,forward把这个变量转换成右值类型。在函数体内使用这个变量时,就可以当作右值使用了。如果形参变量是左值,则不进行这个转换。我可以透露,forward是根据<>内的信息判断该不该转换的。

简化版本:

介绍了这么多和右值有关的事情,而且远远没有说透彻。右值似乎是个麻烦。舍弃这么麻烦也是可以的,不支持右值。我希望最好还是支持右值。代码如下:

template <typename T,typename... Args>
auto TimeMonitorFunc(long long& time, T& func, Args... params)
{
	long long  start_timestamp = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
	auto ret = func(params...);
	long long end_timestamp = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
	time = end_timestamp - start_timestamp;
	return ret;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章