(C++模板程式設計):通過遞迴組合、tuple及基類引數包展開引數包

Asinmy發表於2020-11-11

目錄

通過遞迴組合方式展開引數包

通過tuple和遞迴呼叫展開引數包

基類引數包的展開:演示一下某個類的基類也可以是可變參

特化

通過遞迴組合方式展開引數包

  • 組合關係也稱為複合關係,實際上就是 一種包含關係

class B
{
	//.....
};
class A
{
public:
	B b;  //A中包含B物件,b作為類A的成員變數
};

通過遞迴組合方式示例

//主模板定義(泛化版本的類别範本)
template <typename ...Args>
class myclasst
{
public:
	myclasst()
	{
		printf("myclasst::myclasst()泛化版本執行了,this = %p\n", this);
	}
};
//template <typename ...Args>class myclasst; //主模板宣告(前向宣告/前置宣告)

template <typename First, typename ... Others>
class myclasst<First, Others...> //:private myclasst<Others...> //偏特化
{
public:
	myclasst() :m_i(0)
	{
		printf("myclasst::myclasst()偏特化版本執行了,this = %p,sizeof...(Others)=%d\n", this, sizeof...(Others));
	}

	myclasst(First parf, Others... paro) :m_i(parf) , m_o(paro...)   //, myclasst<Others...>(paro...)
	{
		cout << "---------------------begin-----------------" << endl;
		printf("myclasst::myclasst(parf,...paro)執行了,this = %p\n", this);
		cout << "m_i = " << m_i << endl;
		cout << "---------------------end-----------------" << endl;
	}
	First m_i;
	myclasst<Others...> m_o; //****************
};
template<>
class myclasst<> //一個特殊的特化版本,看起來象全特化,不是全特化,可變參模板不存在全特化
{
public:
	myclasst()
	{
		printf("myclasst::myclasst()特殊的特化版本執行了,this = %p\n", this);
	}
};
  • 呼叫
myclasst<int, float, double> myc(12, 13.5, 23);
  • 輸出

  • 關係圖

通過tuple和遞迴呼叫展開引數包

  • tuple:元組——可變參類别範本
tuple<float, int, int> mytuple(12.5f, 100, 52); //一個tuple(元組),一堆各種型別資料的組合
//元組和列印,用標準庫中的get(函式模板)
cout << get<0>(mytuple) << endl;  //12.5f
cout << get<1>(mytuple) << endl;  //100
cout << get<2>(mytuple) << endl;  //52

通過tuple和遞迴呼叫展開引數包示例

//泛化版本
template <int mycount,int mymaxcount,typename ...T> //mycount用於統計,從0開始,mymaxcount表示引數數量,可以用sizeof...取得。
class myclasst4
{
public:
	//靜態成員函式,藉助tuple(型別),藉助get,就能夠把每個引數提取出來
	static void mysfunc(const tuple<T...>& t)
	{
		cout << "value = " << get<mycount>(t) << endl; //可以把每個引數取出來並輸出
		myclasst4< mycount + 1, mymaxcount, T...>::mysfunc(t); //計數每次+1,這裡是遞迴呼叫,自己呼叫自己
	}
};

//偏特化版本,用於結束遞迴呼叫
template <int mymaxcount, typename ...T>
class myclasst4<mymaxcount, mymaxcount, T...> //注意<>中兩個都是mymaxcount
{
public:
	static void mysfunc(const tuple<T...>& t)
	{
		//這裡其實不用幹啥
	}
};


//可變參函式模板
template <typename ...T>
void myfunctuple(const tuple<T...>& t)
{
	myclasst4<0, sizeof...(T), T...>::mysfunc(t);//這裡注意,第一個引數是0,表示計數從寧0開始
}
  • 呼叫
tuple<float, int, int> mytuple(12.5f, 100, 52);
myfunctuple(mytuple);
  • 輸出結果

基類引數包的展開:演示一下某個類的基類也可以是可變參

template<typename... myclassPList>
class myclasst5 : public myclassPList...
{
public:
	myclasst5() : myclassPList()...
	{
		cout << "myclasst5::myclasst5,this = " << this << endl;
	}
};
class PA1
{
public:
	PA1()
	{
		cout << "PA1::PA1,this = " << this << endl;
	}
private:
	char m_s1[100];
};
class PA2
{
public:
	PA2()
	{
		cout << "PA2::PA2,this = " << this << endl;
	}
private:
	char m_s1[200];
};

class PA3
{
public:
	PA3()
	{
		cout << "PA3::PA3,this = " << this << endl;
	}
private:
	char m_s1[300];
};
  • 呼叫
myclasst5<PA1, PA2, PA3> obj;
cout << "sizeof(obj)=" << sizeof(obj) << endl;
  • 輸出

特化

  • 可變參模板不存在全特化,所以只有偏特化
template<typename ...Args> //泛化版本
class myclasst
{
public:
	myclasst()
	{
		printf("myclasst泛化版本執行了,this=%p,sizeof...(Args)=%d\n", this, sizeof...(Args));
	}
};

template<typename First,typename...Others>
class myclasst<First, Others...> //特化版本
{
public:
	myclasst()
	{
		printf("myclasst<First, Others...>偏特化版本執行了,this=%p,sizeof...(Others)=%d\n", this, sizeof...(Others));
	}
};

template<typename Arg>
class myclasst <Arg>
{
public:
	myclasst()
	{
		printf("myclasst<Arg>偏特化版本執行了,this=%p\n", this);
	}
};

template<typename Arg1,typename Arg2>
class myclasst <Arg1,Arg2>
{
public:
	myclasst()
	{
		printf("myclasst<Arg1,Arg2>偏特化版本執行了,this=%p\n", this);
	}
};
  • 呼叫
myclasst<int> myc1;
myclasst<int,float> myc2;
myclasst<int,float,double> myc3;
myclasst<int,float,double,char> myc4;
myclasst<> myc5;
  • 輸出

相關文章