微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

std::decay 源码分析

背景:

 c++标准库里边很多地方都用到了decay,网上也有很多资料也介绍了decay,大多都是讲怎么用,没有从源码分析,类型退化的用法以及源码分析

std::decay demo

C++
#include <type_traits>
 
template <typename T, typename U>
struct decay_equiv :
    std::is_same<typename std::decay<T>::type, U>::type
{};
template <typename T, typename U>
constexpr bool is_decay_equ = decay_equiv<T, U>::value;
 
int main()
{
    static_assert(
        is_decay_equ<int, int> &&
        ! is_decay_equ<int, float> &&
        is_decay_equ<int&, int> &&
        is_decay_equ<int&&, int> &&
        is_decay_equ<const int&, int> &&
        is_decay_equ<int[2], int*> &&
        ! is_decay_equ<int[4][2], int*> &&
        ! is_decay_equ<int[4][2], int**> &&
        is_decay_equ<int[4][2], int(*)[2]> &&
        is_decay_equ<int(int), int(*)(int)>
    );
}

这里可以看的出来,经过decay过后int[4][2] 退化成  int(*)[2],int(int) 退化成int(*)(int),感觉挺神奇的,就从源码角度来看它是怎么做到的

std::decay 源码

C++
template <class _Tp>
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 <class _Tp> static _Tp& __test(int);
    template <class _Tp> static __two __test(...);
};

template <class _Tp>
struct __is_referenceable : integral_constant<bool,
    _IsNotSame<decltype(__is_referenceable_impl::__test<_Tp>(0)), __two>::value> {};

__is_referenceable_impl 这里会用SFINAE 的原则,如果是可以引用会推到成_Tp&, 否则会推到成__two,这也就是下边_IsNotSame会判定它类型是否一致,也就是说多为数组,以及函数,__is_referenceable<_Up>::value>::type 推到出的是false

接下来看下__decay 的定义

__decay

C++
template <class _Up, bool>
struct __decay {
    typedef _LIBCPP_NODEBUG_TYPE typename remove_cv<_Up>::type type;
};

template <class _Up>
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

通过上边可以看的出来,数组与函数具体是怎么退出成指针的。设计挺有意思的

原文地址:https://www.jb51.cc/wenti/3286090.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐