C++?折疊參數(shù)包詳解(悄然增強編程效率)
前言
本節(jié)將為大家?guī)碚郫B參數(shù)包的詳細講解,折疊參數(shù)包為C++模板編程提供了更加靈活和強大的工具,可以提高代碼的簡潔性和可讀性,看完后希望對你有收獲
一、介紹
折疊參數(shù)就是一個參數(shù)包, 代表是多個未知,tuple元組就是一個折疊參數(shù)的使用
折疊參數(shù)類型:
typename ...Args:Args參數(shù)包的包名 ,本質(zhì)是聲明一個Args折疊參數(shù)類型Args ...arg:折疊參數(shù)包類型的變量...:理解為多個意思
二、函數(shù)模板中使用折疊參數(shù)
1、遞歸方式展開
遞歸方式的展開是比較好理解的,每一次調(diào)用第二個print函數(shù)就打印一次data,然后又調(diào)用自己,這時候參數(shù)包也剝離了一個參數(shù),也就是調(diào)用自己會打印下一個data
有的同學看了下面的代碼可能會疑惑,為什么會有兩個函數(shù),這是因為上面的函數(shù)為終止函數(shù),也就是當?shù)诙€函數(shù)參數(shù)包中只有一個參數(shù)時調(diào)用第一個函數(shù)
template <typename _Ty>
void print(_Ty data)
{
cout << data << endl;
}
template <typename _Ty,typename ...Args>
void print(_Ty data, Args ...args)
{
cout << data << "\t";
print(args...);
}2、列表數(shù)據(jù)展開
這個的難點和重點在于initializer_list<int>{(printData(args), 0)...};,這一行代碼用到了列表和逗號表達式的特性,不用說列表的每個值最后都被初始化為0,但是列表的每個值被初始化為0的時候,他們會先執(zhí)行printData(args(n)),也就是會不斷打印,參數(shù)包不斷展開
template <typename _Ty>
void printData(_Ty data) {
cout << data << "\t";
}
template <typename ...Args>
void printArgs(Args ...args)
{
initializer_list<int>{(printData(args), 0)...};
cout << endl;
}3、完美轉(zhuǎn)發(fā)的方式展開
完美轉(zhuǎn)發(fā)一般是用來統(tǒng)一接口,也就是有許多函數(shù),他們的參數(shù)數(shù)量、類型不同,我們把他們統(tǒng)一為只用函數(shù)名就可以調(diào)用該函數(shù),且不減少其原功能
這里我們用仿函數(shù)接收一下用bind綁定的函數(shù)以及參數(shù)包,注意這里函數(shù)和參數(shù)包綁定的時候都用了完美轉(zhuǎn)發(fā)
什么是完美轉(zhuǎn)發(fā)吶?forword是為了解決在函數(shù)模板中,使用右值引用參數(shù)(T&&),傳遞右值進去以后,類型會變?yōu)樽笾档膯栴}。當傳入的參數(shù)是一個對象時,右值變左值就會出問題,因為左值調(diào)用拷貝構(gòu)造,右值調(diào)用移動構(gòu)造。本來可以用移動構(gòu)造提高效率,卻因為右值變成左值,調(diào)用了拷貝構(gòu)造。所以我們要把它變回去!實參傳的是右值,進入函數(shù)體還是右值,這就是完美轉(zhuǎn)發(fā)
class Test
{
public:
void printk()
{
if (func) func();
}
template <typename Func,typename ...Args>
void connect(Func&& f, Args&& ...args) //右值引用
{
func = bind(forward<Func>(f), forward<Args>(args)...);
}
protected:
function<void()> func;
};
void sum(int a, int b)
{
cout<< a + b;
}
int main()
{
Test test;
test.connect(sum, 1, 2);
test.printk();
test.connect([](int a, int b) {cout << endl << a + b; }, 3, 8);
test.printk();
return 0;
}上面的例子中通過connect綁定函數(shù)和參數(shù)包,實現(xiàn)統(tǒng)一接口的功能,通過printK函數(shù)調(diào)用
三、類模板中使用折疊參數(shù)
1、繼承+模板特化的方式展開
類中實現(xiàn)折疊參數(shù),前兩個類是必須,對應上面的終止函數(shù),繼承的時候要寫清楚public Test<Args...>,還有就是第三個類必須要一個無參構(gòu)造函數(shù),且?guī)?shù)包的的構(gòu)造函數(shù)初始化時要調(diào)用子類的構(gòu)造函數(shù),還有就是打印的時候要一層一層的,采用繼承+模板特化就是一代一代的
template <typename ...Args>
class Test;
template<>
class Test<> {};
template <typename _Ty, typename ...Args>
class Test<_Ty, Args...> :public Test<Args...>
{
public:
Test() {}
Test(_Ty data, Args ...args) :data(data), Test<Args...>(args...) {}
Test<Args...>& getObject() { return *this; }
_Ty& getData() { return data; }
protected:
_Ty data;
};
void testOne()
{
Test<string, int, double> test("fsdjf", 32, 3.23);
cout << test.getData() << "\t" << test.getObject().getData() << "\t" << test.getObject().getObject().getData() << endl;
}2、遞歸的方式展開
遞歸這一種就是把自己當對象調(diào)用,其它的和上面相同
template <typename ...Args>
class my_tuple;
template<>
class my_tuple<> {};
template <typename _Ty, typename ...Args>
class my_tuple<_Ty, Args...>
{
public:
my_tuple() {}
my_tuple(_Ty data, Args ...args) :data(data),args(args...) {}
_Ty& getData() { return data; }
my_tuple<Args...>& getObject() { return *this; }
protected:
_Ty data;
my_tuple<Args...> args;
};
void testTwo()
{
Test<string, int, double> test("fsdjf", 32, 3.23);
cout << test.getData() << "\t" << test.getObject().getData() << "\t" << test.getObject().getObject().getData() << endl;
}到此這篇關于C++ 折疊參數(shù)包悄然增強編程效率的文章就介紹到這了,更多相關C++ 折疊參數(shù)包內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++中的函數(shù)指針與函數(shù)對象的總結(jié)
以下是對C++中的函數(shù)指針與函數(shù)對象的使用進行了詳細的分析介紹,需要的朋友可以參考下2013-07-07

