【C++11】C++類型完全退化(拓展std::decay的功能)

C++11提供了一個模板類,來爲我們移除類型中的一些特性,比如引用、常量、volatile,但是注意不包括指針特性,這個類就是std::decay,在頭文件type_traits(類型萃取)中。比如:

// 代碼1:
class myclass{};
std::decay<const myclass &>::type var1;
代碼1中的變量var1的類型是myclass。如果我們希望將指針特性也退化掉,則需要自己寫代碼實現。參考std::decay的代碼,其實並不難寫:

// 代碼2:	
/* 實現無指針退化,即除了兼容std::decay的特性之外,還把指針退化掉 */
	template<class _Ty>
	struct np_decay
	{	// determines decayed version of _Ty
		typedef typename std::remove_reference<_Ty>::type _Ty1;  // 移除引用特性
		typedef typename std::remove_pointer<_Ty1>::type _Ty2;	 // 將指針也退化掉

		typedef typename std::_If<std::is_array<_Ty2>::value,	 // 數組的話 
			typename std::remove_extent<_Ty2>::type *,	 // 取出數組的原始類型
				typename std::_If<std::is_function<_Ty2>::value, // 不是數組,如果是函數
				typename std::add_pointer<_Ty2>::type,		 // 變成函數指針
				typename std::remove_cv<_Ty2>::type>::type	 // 不是函數,移除CV特性(const和volatile)
		>::type type;
	};
在std::decay的代碼的基礎上添加了如下代碼:

typedef typename std::remove_pointer<_Ty1>::type _Ty2;
將移除引用特性後的類型_Ty1再移除指針特性。運行如下的代碼:

// 代碼3:
np_decay<myclass**>::type var2;
代碼3中的var2的類型是myclass*,似乎和說好的把指針退化掉不一樣啊。不過代碼沒錯,這不是myclass**退化成myclass*了嗎。下面就來寫代碼徹底解決這個問題:

// 代碼4:
/* 實現完全退化,將一個類型的所有修飾符全部去掉 */
template<class T, bool issame =
	std::is_same<T, typename np_decay<T>::type>::value
> struct fulldecay;

template<class T>
struct fulldecay<T, false>
	: fulldecay<typename np_decay<T>::type>
{};

template<class T>
struct fulldecay<T, true>
{
	typedef T type;
};
代碼4定義了一個模板結構體fulldecay,有兩個模板參數分別是T和issame。思路是這樣的,使用np_decay去退化T,得到類型typename np_decay<T>::type,如果退化後的類型和T是一樣的,則issame爲true。然後fulldecay偏特化,當issame爲false時,結構體fulldecay內部什麼都沒有,但是繼承自用typename np_decay<T>::type實例化模板參數T的自身;只有當issame爲true時,結構體fulldecay纔不再繼承,而是在內部定義當前的T爲type。也就是說通過不斷遞歸繼承,每繼承一次退化一次,退化到沒效果了就是全部特性都移除了,這時候的T作爲結果的type類型。運行如下的代碼體驗一下吧:

// 代碼5:
fulldecay<myclass const * const volatile * const &&>::type var3;
代碼5中的var3的類型就是myclass,最簡單的驗證方法是在myclass寫一個有參構造函數,然後你就會看到var3底下的紅線(VS)或者收到編譯器的error——myclass不存在默認構造函數(var3需要傳遞構造函數參數)。可見經過fulldecay處理後,經過再多修飾的類型都會變回原形。






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