码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • C++ shared_ptr类型转换的实现原理与type traits类型萃取


    思考下面这个问题:

    #include 
    #include 
    using namespace std;
    
    class A{
    public:
        int data;
    };
    
    class B : public A{
    };
    
    template <typename _Ty>
    class TypeCast{
    };
    
    int main()
    {
        shared_ptr<B> b = make_shared<B>();
        shared_ptr<A> a = b;	// 正确,为何能将b转成a?
    
        TypeCast<B> tb;
        TypeCast<A> ta = tb;	// 错误
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    上面的代码,很容易理解,B虽然是A的子类,但是TypeCast和TypeCast并无关系,不能隐式转换能理解。那shared_ptr是如何实现的呢?

    很容易想到,此隐式类型转换是通过构造函数实现的。

    修改一下TypeCast,也能实现和shared_ptr一样的隐式类型转换:

    template <typename _Ty>
    class TypeCast{
    
    public:
    TypeCast() = default;
    
    template<typename _Ty2>
    TypeCast(const TypeCast<_Ty2>& ){
    }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    是可以实现了,但是又出现一个新问题,任何一个TypeCast模板对象都能使用此构造函数,即使_Ty2不是Ty的子类也能调用此构造函数实现隐式转换。

    TypeCast<A> ta = tb;	// 正确
    class C{};
    TypeCast<C> tc = ta;	// 正确
    
    • 1
    • 2
    • 3

    如何限定必须要有父子关系的_Ty才能调用此构造函数?

    使用type_traits类型萃取。

    通过type_traits可以实现在编译期计算、查询、判断、转换和选择,增强了泛型编程的能力。

    template <typename _Ty>
    class TypeCast{
    
    public:
    TypeCast() = default;
    
    // 编译器 vc++ 2019,gcc的实现不同
    template <class _Ty2, enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
    TypeCast(const TypeCast<_Ty2>& ){
    }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    TypeCast<A> ta = tb;	// 正确,TypeCast ta = TypeCase::TypeCase(tb);
    class C{};
    TypeCast<C> tc = ta;	// 错误
    
    • 1
    • 2
    • 3

    类型萃取是如何实现的?

    
    using _my_type = enable_if_t<_SP_pointer_compatible<B, A>::value, int>;
    // _my_type 是 int
    
    using _my_type2 = enable_if_t<_SP_pointer_compatible<B, C>::value, int>;
    // _my_type2 是 error type
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    通过type_traits的is_convertible,判断类型T是否能转换为类型U,enable_if_t返回一个指定的类型int,并设置默认值为0。

    在msvc和gcc中的shared_ptr构造函数模板是不同的。

    
    // msvc,直接通过判断类型是否能转换来推断是否能调用此构造函数
    // 若构造成功,模板定义:template;构造失败则无类型:template
        template <class _Ty2, enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
        shared_ptr(const shared_ptr<_Ty2>& _Other) noexcept {
            // construct shared_ptr object that owns same resource as _Other
            this->_Copy_construct_from(_Other);
        }
        
    // gcc,通过判断父类__shared_ptr是否有指定参数的构造函数来推断是否可调用此构造函数,
    // 若能构造成功,模板定义:template,若不能构造则类型错误:template
        template<typename _Yp, typename = _Constructible<const shared_ptr<_Yp>&>>
    	shared_ptr(const shared_ptr<_Yp>& __r) noexcept
            : __shared_ptr<_Tp>(__r) { }
            
        // __shared_ptr的此构造函数判断类型是否能转换来推断是否能调用此构造函数
        template<typename _Yp, typename = _Compatible<_Yp>>
    	__shared_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept
    	: _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount)
    	{ }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    // gcc 和 msvc 的实现
    #if _WIN32
    template <class _Yty, class _Ty>
    using _sp_convertible = _SP_pointer_compatible<_Yty, _Ty>;
    #else
    template <typename _Yp_ptr, typename _Tp_ptr>
    using _sp_convertible = __sp_compatible_with<_Yp_ptr*, _Tp_ptr*>;
    #endif
    
    template <typename _Ty>
    class TypeCast
    {
    
    public:
        TypeCast() = default;
    
        template <class _Ty2, enable_if_t<_sp_convertible<_Ty2, _Ty>::value, int> = 0>
        TypeCast(const TypeCast<_Ty2> &)
        {
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  • 相关阅读:
    HCNP Routing&Switching之DHCP中继
    使用HierarchyViewer工具分析布局
    升本政治冲冲冲
    猿创征文|我的Python成长之路
    算法------时间复杂度
    最大电流1A,峰值电流1.1A单节锂离子电池充电芯片DP4056使用注意事项
    计算机网络原理复习汇总
    在 Rainbond 上使用 Curve 云原生存储
    用Unity重现《空洞骑士》的苦痛之路(2)——地图篇
    Nginx配置使用详解
  • 原文地址:https://blog.csdn.net/lwwl12/article/details/133746633
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号