包裝器這種編程方法是內建到python的語言裏的。C++也能很容易實現這個功能。
本文的包裝器能爲任意一個可調用對象附加一個輸出執行時間的功能。我們把這個包裝器實現成函數TimeMonitorFunc。下面先進行概述,然後介紹一下具體實現。
概述:
(1)功能:
任何一個可調用對象(例如函數)都能和TimeMonitorFunc結合在一起使用。這個包裝器的功能是執行任意一個可調用對象並得出執行時間。
(2)原型:
template <typename T,typename... Args>
decltype(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;
}
template <typename T,typename... Args>
decltype(auto) TimeMonitorFunc(long long& time, T&& func, Args&&... params)
{
long long start_timestamp = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
decltype(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;
int n = 10;
string str = TimeMonitorFunc(run_duration, ToString,n, 20, 'a');
cout << str << " " << run_duration <<endl;
getchar();
}
auto作爲返回值是C++14特性,decltype(auto) 的作用和auto類似,也是表示返回值的類型通過推到獲得,但類型的推導規則和auto略有不同,本文暫不討論推導規則。
Args&& 、T&& func 、forward<>結合起來實現參數的完美轉發。這個包裝器的本質就是TimeMonitorFunc嵌套了一個func,func的參數是通過TimeMonitorFunc的參數(params)獲得的。我們希望傳遞給func的實參是傳遞給TimeMonitorFunc的實參本身,而不是它的副本(按值傳遞),並且實參的const、volation、左值、右值等屬性不變。
Args&&和T&& fun聲明的是萬能引用類型的模板形參。這兩個模板形參實例化爲普通形參時,在形參類型中保留了實參的const、volation、左值、右值等屬性,並且形參被實例化爲引用類型(左值引用或右值引用),而非值類型。“decltype(auto) TimeMonitorFunc(run_duration, ToString,n, 20, 'a')”實例化的結果是:“decltype(auto) TimeMonitorFunc(__int64& time,string(__cdecl &)(int,int,char),int& n1,int&& n2,char&& c)”。形參變量n2和c雖然聲明爲右值引用類型,但是這兩個變量在作爲實參傳遞給func時(形如:func(n1,n2,c)),對func來說n2、c是左值。存在這樣一個事實,右值引用類型的變量本身是左值。forward的作用是把右值引用類型的形參變量轉換爲右值,左值引用類型的形參變量保持左值不變。最終TimeMonitorFunc原原本本的把參數轉發給了func。