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

C++11提供了一个模板类,来为我们移除类型中的一些特性,比如引用、常量、volatile,但是注意不包括指针特性,这个类就是std::decay,在头文件type_traits(类型萃取)中。比如:

// 代码1:
class myclass{};
std::decay::type var1;
代码1中的变量var1的类型是myclass。如果我们希望将指针特性也退化掉,则需要自己写代码实现。参考std::decay的代码,其实并不难写:

// 代码2:	
/* 实现无指针退化,即除了兼容std::decay的特性之外,还把指针退化掉 */
	template
	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::value,	 // 数组的话 
			typename std::remove_extent<_Ty2>::type *,	 // 取出数组的原始类型
				typename std::_If::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::type var2;
代码3中的var2的类型是myclass*,似乎和说好的把指针退化掉不一样啊。不过代码没错,这不是myclass**退化成myclass*了吗。下面就来写代码彻底解决这个问题:

// 代码4:
/* 实现完全退化,将一个类型的所有修饰符全部去掉 */
template::type>::value
> struct fulldecay;

template
struct fulldecay
	: fulldecay::type>
{};

template
struct fulldecay
{
	typedef T type;
};
代码4定义了一个模板结构体fulldecay,有两个模板参数分别是T和issame。思路是这样的,使用np_decay去退化T,得到类型typename np_decay::type,如果退化后的类型和T是一样的,则issame为true。然后fulldecay偏特化,当issame为false时,结构体fulldecay内部什么都没有,但是继承自用typename np_decay::type实例化模板参数T的自身;只有当issame为true时,结构体fulldecay才不再继承,而是在内部定义当前的T为type。也就是说通过不断递归继承,每继承一次退化一次,退化到没效果了就是全部特性都移除了,这时候的T作为结果的type类型。运行如下的代码体验一下吧:

// 代码5:
fulldecay::type var3;
代码5中的var3的类型就是myclass,最简单的验证方法是在myclass写一个有参构造函数,然后你就会看到var3底下的红线(VS)或者收到编译器的error——myclass不存在默认构造函数(var3需要传递构造函数参数)。可见经过fulldecay处理后,经过再多修饰的类型都会变回原形。






你可能感兴趣的:(C++,使用技巧)