当前位置: 首页 > news >正文

Effective C++ 条款45:运用成员函数模板接受所有兼容类型

Effective C++ 条款45:运用成员函数模板接受所有兼容类型


核心思想使用成员函数模板(member function templates)生成可接受兼容类型的函数,特别是泛型拷贝构造函数和赋值操作符,同时避免抑制编译器生成的默认特殊成员函数。

⚠️ 1. 智能指针的类型转换问题

问题根源

  • 希望智能指针能模拟内置指针的隐式转换(如派生类指针到基类指针)
  • 模板实例化后不同模板参数生成的是不同类,无法直接转换
  • 需要为每种可能的兼容类型单独编写构造函数,不现实

错误示例

template<typename T>
class SmartPtr {
public:explicit SmartPtr(T* realPtr); // 原始指针构造函数// 希望支持以下转换,但无法实现:// SmartPtr<Base> = SmartPtr<Derived>// SmartPtr<const T> = SmartPtr<T>
};

🚨 2. 成员函数模板解决方案

解决方案

  • 声明成员函数模板(泛型拷贝构造函数)
  • 使用类型约束确保安全转换

优化实现

template<typename T>
class SmartPtr {
public:template<typename U>SmartPtr(const SmartPtr<U>& other)  // 泛型拷贝构造: heldPtr(other.get()) { }     // 使用get()获取原始指针T* get() const { return heldPtr; } // 获取原始指针private:T* heldPtr; // 持有原始指针
};

类型安全约束

  • 添加编译期类型检查,确保U可隐式转换为T
template<typename T>
class SmartPtr {
public:template<typename U, typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>SmartPtr(const SmartPtr<U>& other): heldPtr(other.get()) { }// ...
};

⚖️ 3. 赋值操作与兼容性处理

问题场景

  • 需要支持不同类型的智能指针赋值
  • 同时要避免编译器自动生成默认拷贝操作

解决方案

  • 为赋值操作定义成员模板函数
  • 显式声明普通拷贝操作以避免被模板隐藏

完整实现

template<typename T>
class SmartPtr {
public:// 泛型拷贝构造template<typename U, typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>SmartPtr(const SmartPtr<U>& other);// 显式声明普通拷贝构造和赋值(防止被模板隐藏)SmartPtr(const SmartPtr&); SmartPtr& operator=(const SmartPtr&);// 泛型赋值操作符template<typename U, typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>SmartPtr& operator=(const SmartPtr<U>& other);// ... 其他成员 ...
};

注意事项

  • 成员函数模板不改变语言规则:拷贝构造函数不会阻止编译器生成默认拷贝构造函数
  • 若需要完全控制,可显式定义或使用=default/=delete

💡 关键设计原则

  1. 使用成员函数模板实现泛型构造
    成员函数模板可生成接受任意兼容类型的构造函数和赋值函数

    template<typename T>
    class SharedPtr {
    public:template<typename Y>explicit SharedPtr(Y* p);  // 从任意类型指针构造template<typename Y>SharedPtr(const SharedPtr<Y>& r); // 兼容类型拷贝构造
    };
    
  2. 添加类型转换约束
    使用std::enable_if和类型特征确保安全转换

    template<typename T>
    class SmartPtr {template<typename U, typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>SmartPtr(const SmartPtr<U>&);
    };
    
  3. 显式声明默认函数
    避免成员模板隐藏编译器生成的默认函数

    template<typename T>
    class SmartPtr {
    public:// 显式声明拷贝操作SmartPtr(const SmartPtr&); SmartPtr& operator=(const SmartPtr&);// 成员模板构造函数...
    };
    

实战:跨类型智能指针赋值

class Base { /*...*/ };
class Derived : public Base { /*...*/ };SmartPtr<Base> pBase(new Base);
SmartPtr<Derived> pDerived(new Derived);// 使用成员模板实现兼容类型赋值
pBase = pDerived;  // 正确:通过泛型赋值操作符// 错误示例:类型不兼容
SmartPtr<int> pInt(new int);
// pBase = pInt; // 编译错误:类型约束阻止转换

类型特征约束进阶

// 使用更精确的约束:派生关系
template<typename T>
class SmartPtr {template<typename U, typename = std::enable_if_t<std::is_base_of_v<T, U> || std::is_convertible_v<U*, T*>>>SmartPtr(const SmartPtr<U>&);
};

总结成员函数模板允许类模板生成接受任意兼容类型的函数,是实现泛型拷贝构造和赋值操作的关键技术。通过添加编译期类型约束(如std::enable_if和类型特征)确保转换安全,同时显式声明默认拷贝操作以避免被模板隐藏。这一技术广泛用于智能指针、迭代器等需要类型灵活性的场景,是编写高级模板代码的必备技能。

http://www.xdnf.cn/news/1311769.html

相关文章:

  • Linux怎么查看服务器开放和启用的端口
  • 【原理】C# 字段、属性对比及其底层实现
  • illustrator插件大全 免费插件介绍 Ai设计插件集合 (3)
  • Python语言一键整理xhs评论 基于github的开源项目 MediaCrawler
  • Linux进程概念(四)环境地址变量
  • 同创物流学习记录2·电车
  • 链式二叉树的基本操作——遍历
  • 实时计算 记录
  • 美国服务器环境下Windows容器工作负载基于指标的自动扩缩
  • 从盲区到全域:黎阳之光视频孪生+AI智能算法驱动智慧机场三维感知革命
  • 4.6 Vue 3 中的模板引用 (Template Refs)
  • CSS复习
  • Jenkins安装部署(Win11)和常见配置镜像加速
  • SysTick寄存器(嘀嗒定时器实现延时)
  • 要导入StandardScaler类进行数据标准化,请使用以下语句:
  • VS Code配置MinGW64编译ALGLIB库
  • 《C语言程序设计》笔记p10
  • 【数据分享】上市公司供应链成本分摊数据(2007-2024)
  • 【数据结构】-2- 泛型
  • leetcodehot100 矩阵置零
  • 基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
  • 谷歌手机刷机和面具ROOT保姆级别教程
  • 利用 Java 爬虫按图搜索淘宝商品(拍立淘)实战指南
  • 《解耦的艺术:Python 观察者模式在 GUI 与事件驱动中的实战》
  • cPanel Python 应用部署流程
  • 【自动化运维神器Ansible】Ansible逻辑运算符详解:构建复杂条件判断的核心工具
  • Scala面试题及详细答案100道(11-20)-- 函数式编程基础
  • PCIE EP 框架
  • C#单元测试(xUnit + Moq + coverlet.collector)
  • RK3568 NPU RKNN(四):RKNN-ToolKit2性能和内存评估