背景:
c++标准库里边很多地方都用到了decay,网上也有很多资料也介绍了decay,大多都是讲怎么用,没有从源码分析,类型退化的用法以及源码分析
std::decay demo
| C++ #include template struct decay_equiv : std::is_same::type, U>::type {}; template constexpr bool is_decay_equ = decay_equiv::value; int main() { static_assert( is_decay_equ && ! is_decay_equ && is_decay_equ && is_decay_equ && is_decay_equ && is_decay_equ && ! is_decay_equ && ! is_decay_equ && is_decay_equ && is_decay_equ ); } |
这里可以看的出来,经过decay过后int[4][2] 退化成 int(*)[2],int(int) 退化成int(*)(int),感觉挺神奇的,就从源码角度来看它是怎么做到的
std::decay 源码
| C++ template struct _LIBCPP_TEMPLATE_VIS decay { private: typedef _LIBCPP_NODEBUG_TYPE typename remove_reference<_Tp>::type _Up; public: typedef _LIBCPP_NODEBUG_TYPE typename __decay<_Up, __is_referenceable<_Up>::value>::type type; }; |
可以看的出来,以上来就去除了_Tp 的引用, __is_referenceable<_Up>::value判定是否可引用
__is_referenceable
| C++ struct __is_referenceable_impl { template static _Tp& __test(int); template static __two __test(...); };
template struct __is_referenceable : integral_constant _IsNotSame(0)), __two>::value> {}; |
__is_referenceable_impl 这里会用SFINAE 的原则,如果是可以引用会推到成_Tp&, 否则会推到成__two,这也就是下边_IsNotSame会判定它类型是否一致,也就是说多为数组,以及函数,__is_referenceable<_Up>::value>::type 推到出的是false
接下来看下__decay 的定义
__decay
| C++ template struct __decay { typedef _LIBCPP_NODEBUG_TYPE typename remove_cv<_Up>::type type; };
template struct __decay<_Up, true> { public: typedef _LIBCPP_NODEBUG_TYPE typename conditional < is_array<_Up>::value, typename remove_extent<_Up>::type*, typename conditional < is_function<_Up>::value, typename add_pointer<_Up>::type, typename remove_cv<_Up>::type >::type >::type type; }; |
上边可以看出来有2个版本,上边是泛化版本针对普通类型,会先调用remove_cv这个,去除类型的const与volatile
最主要看下边的特化版本的意思,这里需要一部分一部分分析,首先看下
| C++ typename conditional < is_array<_Up>::value, typename remove_extent<_Up>::type*,...> |
它先通过conditional 条件判断, is_array<_Up>::value,_Up 是不是数组,如果是数组,他会typename remove_extent<_Up>::type 它会移除一个扩展[],用*号替代,如果不是数组呢
接着看
| C++ typename conditional < is_function<_Up>::value, typename add_pointer<_Up>::type, typename remove_cv<_Up>::type >::type |
它会判断是否是函数,如果是函数,就add_pointer<_Up>, 转换成指针,否则移除remove_cv
通过上边可以看的出来,数组与函数具体是怎么退出成指针的。设计挺有意思的