【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处理后,经过再多修饰的类型都会变回原形。






  • 13
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
std::remove_cv和std::decay都是C++标准库中的模板类,用于处理类型的特性。 std::remove_cv用于移除类型中的const和volatile修饰符。在C++11中,我们需要使用typename std::remove_cv<T>::type的形式来获取移除修饰符后的类型。而在C++14及其后的标准中,我们可以使用std::remove_cv_t<T>的形式来简化代码。\[2\] std::decay用于对一个类型进行退化处理。它会移除类型中的引用修饰符,并将数组类型转换为指针类型。在C++11中,我们需要使用typename std::decay<T>::type的形式来获取退化后的类型。\[1\]在C++14及其后的标准中,我们可以使用std::decay_t<T>的形式来简化代码。\[2\] 总结来说,std::remove_cv用于移除类型中的const和volatile修饰符,而std::decay用于对类型进行退化处理,移除引用修饰符并将数组类型转换为指针类型。 #### 引用[.reference_title] - *1* [C++11std::is_same和std::decay使用与源码解析](https://blog.csdn.net/weixin_43798887/article/details/118311126)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [【C++ 泛型编程 入门篇】C++元模版中std::remove_reference_t和std::remove_cv_t的运用](https://blog.csdn.net/qq_21438461/article/details/131193312)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [C++std::is_same与std::decay](https://blog.csdn.net/sinat_31608641/article/details/124598754)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值