c++ enable_if 的簡單使用


在 c++ 中,有一個東西叫做 template,也就是中文里的模板,c++ 的 STL 以及許多函數都用到了 template,template 指出了泛型編程的一條道路。
最經典的問題是寫一個函數,返回兩個數的較小值。

inline int min(const int &a,const int &b){
	return a<b?a:b;
}

這段代碼非常淺顯易懂,但是只支持 int 類型的變量,想要支持其他類型,必須通過 c++ 的重載函數才能實現。

inline double min(const double &a,const double &b){
	return a<b?a:b;
}

這樣要寫很多很多函數才能實現,而且還不支持用戶自定義類型,非常不實用。這個時候就容易想到使用 #define 預編譯指令實現。
PS:c++ 重載函數的原理是 SFINAE 原則,不匹配不報錯而是試圖匹配其他的同名函數。

#define min(x,y)((x)<(y)?(x):(y))

盡管這樣實現了要求,但是首先 #define 不安全,其次就是遇到有副作用的運算比如自增運算符就會產生問題……當然可以通過多行 #define 實現。但是最簡單的方法還是模板:

template<typename any>
inline any min(const any &a,const any &b){
	return a<b?a:b;
}

這樣僅此一個函數就實現了所有功能。如果對於用戶自定義的變量進行比較,可以對用戶變量進行重載運算符小於號解決,或者通過模板特化:

struct modint{int data;};
friend inline bool operator<(const modint &x,const modint &y){
	return x.data<y.data;
}// 重載運算符
inline modint min(const modint &x,const modint &y){
	return x.data<y.data?x:y;
}// 模板特化

但是要是不只有一個類型而是一系列類型都要特化模板,比如說為所有 unsigned 類型寫一個 lowbit,這要怎么辦呢?要是全部重載函數,unsigned short,unsigned int,unsigned long,unsigned long long,太多了!而如果直接寫模板有時候又不想傳入 unsigned 類型,這個時候就要用到 enable_if 了。
enable_if 聽上去是個函數實際上是個函數實際上是個 struct,構造十分巧妙,第一個參數強制要求是 true,起到了 if 判斷作用:如果是 false,直接跳過。
這里給出 std 命名空間里 enable_if 的實現方式:

	// Partial specialization for true.
	template<typename _Tp>
		struct enable_if<true, _Tp>
		{ typedef _Tp type; }

再貼一個使用 enable_if 實現的 lowbit:

template<typename any>
inline typename std::enable_if<std::is_unsigned<any>::value,any>::type lowbit(const any &x){
	return x&-x;
}

可以發現原來本來應該寫 any 的位置變成了很長一串:首先由 typename 打頭陣,指出后面是個類型而不是個普通類型,然后是個 enable_if,逗號左邊是判別式,這里使用 std::is_unsigned 進行判別,但是 is_unsigned 本質上也不是個函數沒有返回值,就使用在里面 typedef 的 value 當成返回類型即可,也就是 any,逗號后面是這個函數真正的返回類型,這里直接使用 any 就行了,因為 std::enable_if 也不是個函數,只能使用在 std::enable_if 里 typedef 的 type 當成返回類型即可。至於其他部分和普通模板一模一樣。
為了加深印象,我就放另外一個由 std::enable_if 實現的快讀作為示范:

template <typename any>
typename std::enable_if<std::is_signed<any>::value, fastIO>::type &operator>>(any &t)
{
	t = 0;
	bool y = 0;
	char c = get();
	for (; !isdigit(c); c = get())
		if (c == 45)
			y = true;
	for (; isdigit(c); c = get())
		t = t * 10 + (c ^ 48);
	if (y == 1)
		t = -t;
	return *this;
}
template <typename any>
typename std::enable_if<std::is_unsigned<any>::value, fastIO>::type &operator>>(any &t)
{
	t = 0;
	char c = get();
	for (; !isdigit(c); c = get())
		;
	for (; isdigit(c); c = get())
		t = t * 10 + (c ^ 48);
	return *this;
}
// 自行格式化


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM