特化标准库中的类模板

std::mapstd::less作为载体说明如何特化标准库中的类模板。

std::map容器允许提供一个自定义的比较器。默认行为是让std::map使用一个模板类std::less<>,使用<运算符来比较键。如果想存储一个不能使用<进行比较的类型,可以为此类型特化std::less。例如,假设有一个Person类,存储一个人的姓名、年龄。要把一个人存储在一个按照姓名(年龄)排序的std::map中。所需要做的就是编写一个模板特化std::less<Person>

1. 错误示例

没有特化std::less时企图往std::map放入Person是会报错的,具体如下示例:

#include <iostream>
#include <string>
#include <map>
#include <functional>

class Person
{
public:
    Person():Person("", 0){
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
    Person(const std::string& name, int age):name_(name), age_(age){
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    Person(const Person& p):name_(p.name_), age_(p.age_){
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
    Person& operator=(const Person& p)& {
        name_ = p.name_;
        age_ = p.age_;
        return *this;
    }

    Person(Person&& p) noexcept: name_(p.name_), age_(p.age_){
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
    Person& operator=(Person&& p) & noexcept {
        name_ = p.name_;
        age_ = p.age_;
        return *this;
    }

    virtual ~Person(){
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    std::string getName() const{
        return name_;
    }

    int getAge() const {
        return age_;
    }

private:
    std::string name_;
    int age_;
};

#if 0
namespace std{
    template<>
    struct less<Person>{
        bool operator()(const Person& lhs, const Person& rhs) const {
            //return lhs.getAge() < rhs.getAge();  // 按age_升序
            return lhs.getName() < rhs.getName();  // 按name_升序
        }
    };
}
#endif

int main()
{
    Person p1("ZhangSan", 23);
    Person p2("LiSi", 31);
    Person p3("WangWu", 19);
    Person p4("ChenLiu", 43);

    /* 编译报错:/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bits/stl_function.h:408:20: error: no match for 'operator<' (operand types are 'const Person' and 'const Person')
       报错的原因是未使用类Person对模板类模板类 std::less进行特化(specialization) */
    //std::map<Person, std::string> pmaps{{p1, "ZhangSan@qq.com"}, {p2, "LiSi@qq.com"}, {p3, "WangWu@qq.com"}, {p4, "ChenLiu@qq.com"}};
    std::map<Person, std::string> pmaps;
    pmaps[p1] = "ZhangSan@qq.com";
    pmaps[p2] = "LiSi@qq.com";
    pmaps[p3] = "WangWu@qq.com";
    pmaps[p4] = "ChenLiu@qq.com";

    for(const auto& [k, v]: pmaps){
        std::cout << k.getName() << ", " << k.getAge() << ", " << v << std::endl; 
    }
}

2. 正确示例

可以特化在std命名空间中定义的模板,但不能向std添加新的声明。
std::less模板在<functional>头文件中声明,该头文件定义了所有关系和相等运算符的比较器模板。
使用Person特化std::less时可参考std::less模板在<functional>头文件中的定义,也就是C++在找不到显式特化(如std::less<Person>)时使用的主模板。
使用Person特化std::less后可以使用Person作为std::mapkey,具体如下示例正确的实现:

#include <iostream>
#include <string>
#include <map>
#include <functional>

class Person
{
public:
    Person():Person("", 0){
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
    Person(const std::string& name, int age):name_(name), age_(age){
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    Person(const Person& p):name_(p.name_), age_(p.age_){
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
    Person& operator=(const Person& p)& {
        name_ = p.name_;
        age_ = p.age_;
        return *this;
    }

    Person(Person&& p) noexcept: name_(p.name_), age_(p.age_){
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
    Person& operator=(Person&& p) & noexcept {
        name_ = p.name_;
        age_ = p.age_;
        return *this;
    }

    virtual ~Person(){
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    std::string getName() const{
        return name_;
    }

    int getAge() const {
        return age_;
    }

private:
    std::string name_;
    int age_;
};

namespace std{
    template<>
    struct less<Person>{
        bool operator()(const Person& lhs, const Person& rhs) const {
            //return lhs.getAge() < rhs.getAge();  // 按age_升序
            return lhs.getName() < rhs.getName();  // 按name_升序
        }
    };
}

int main()
{
    Person p1("ZhangSan", 23);
    Person p2("LiSi", 31);
    Person p3("WangWu", 19);
    Person p4("ChenLiu", 43);

    // std::map<Person, std::string> pmaps{{p1, "ZhangSan@qq.com"}, {p2, "LiSi@qq.com"}, {p3, "WangWu@qq.com"}, {p4, "ChenLiu@qq.com"}};  // 这种方式会多调用四次构造、析构
    std::map<Person, std::string> pmaps;
    pmaps[p1] = "ZhangSan@qq.com";
    pmaps[p2] = "LiSi@qq.com";
    pmaps[p3] = "WangWu@qq.com";
    pmaps[p4] = "ChenLiu@qq.com";

    for(const auto& [k, v]: pmaps){
        std::cout << k.getName() << ", " << k.getAge() << ", " << v << std::endl; 
    }
}

输出结果:

Person::Person(const std::string&, int)
Person::Person(const std::string&, int)
Person::Person(const std::string&, int)
Person::Person(const std::string&, int)
Person::Person(const Person&)
Person::Person(const Person&)
Person::Person(const Person&)
Person::Person(const Person&)
ChenLiu, 43, ChenLiu@qq.com
LiSi, 31, LiSi@qq.com
WangWu, 19, WangWu@qq.com
ZhangSan, 23, ZhangSan@qq.com
virtual Person::~Person()
virtual Person::~Person()
virtual Person::~Person()
virtual Person::~Person()
virtual Person::~Person()
virtual Person::~Person()
virtual Person::~Person()
virtual Person::~Person()

Reference

Exploring C++ 11, 2nd Edition.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/604693.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

关于Anaconda常用的命令

常用命令 查看当前环境下的环境&#xff1a;conda env list查看当前conda的版本&#xff1b;conda --version conda create -n your_env_name pythonX.X&#xff08;2.7、3.6等)命令创建python版本为X.X。名字为your_env_name的虚拟环境。your_env_name文件可以在Anaconda安装…

2024第16届成都教育连锁加盟展6月1日举办 免费参观

2024第16届成都教育连锁加盟展6月1日举办 免费参观 邀请函 主办单位&#xff1a; 中国西部教体融合博览会组委会 承办单位&#xff1a;重庆港华展览有限公司 博览会主题&#xff1a;责任教育科技兴邦 幼教、普教、高教、校外教育、K12学科辅导、婴幼儿教育、兴趣辅导、学…

STC8增强型单片机开发

1.C51版本Keil环境搭建 下载地址是 Keil Product Downloads 选择C51进行下载&#xff1a; 2.STC环境添加 STC-ISP下载 进入stc官网 深圳国芯人工智能有限公司-工具软件 3.将STC添加到Keil中 打开stc-isp工具 按照图例点击按钮 选择keil的安装目录&#xff0c;以实际安装目…

Nacos单机模式集成MySQL

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 Nacos支持三种部署…

VALSE 2024 Workshop报告分享┆ 大规模自动驾驶仿真系统研究

视觉与学习青年学者研讨会&#xff08;VALSE&#xff09;旨在为从事计算机视觉、图像处理、模式识别与机器学习研究的中国青年学者提供一个广泛而深入的学术交流平台。该平台旨在促进国内青年学者的思想交流和学术合作&#xff0c;以期在相关领域做出显著的学术贡献&#xff0c…

五月加仓比特币

作者&#xff1a;Arthur Hayes Co-Founder of 100x. 编译&#xff1a;Liam 编者注&#xff1a;本文略有删减 (以下内容仅代表作者个人观点&#xff0c;不应作为投资决策的依据&#xff0c;也不应被视为参与投资交易的建议或意见&#xff09;。 从四月中旬到现在&#xff0c;当你…

动态规划——路径问题:931.下降路径最小和

文章目录 题目描述算法原理1.状态表示&#xff08;经验题目&#xff09;2.状态转移方程3.初始化4.填表顺序5.返回值 代码实现CJava 题目描述 题目链接&#xff1a;931.下降路径最小和 关于这⼀类题&#xff0c;看过我之前的博客的朋友对于状态表示以及状态转移是⽐较容易分析…

Java 中的 HTTP 客户端库OkHttp、Apache HttpClient和HttpUrlConnection

大家好&#xff0c;我是G探险者。 项目开发里面经常会有这么一种场景&#xff1a;与服务器进行 HTTP 通信。一般存在于服务间远程调用的场景 Java 生态系统提供了多种 HTTP 客户端库&#xff0c;每种都有其自己的特点、优势和适用场景。 本文将介绍几种主要的 Java HTTP 客户…

【练习3】

1.将二叉搜索树转为排序的双向链表 (好久没看数据结构&#xff0c;忘完了&#xff0c;学习大佬的代码&#xff09; class Solution { public:Node* prenullptr,*headnullptr; //pre为每次遍历时的前一个节点&#xff0c;head记录头节点Node* treeToDoublyList(Node* root) {if…

Qt应用开发(拓展篇)——图表 QChart

一、前言 QChart是一个图形库模块&#xff0c;它可以实现不同类型的序列和其他图表相关对象(如图例和轴)的图形表示。要在布局中简单地显示图表&#xff0c;可以使用QChartView来代替QChart。此外&#xff0c;线条、样条、面积和散点序列可以通过使用QPolarChart类表示为极坐标…

Vue3 查看真实请求地址

上回说到Vue2查看真实请求地址&#xff0c;那么Vue3该如何查看呢&#xff1f; 传送门&#xff1a; Vue2 查看真实请求地址 1. bypass函数 使用bypass函数获取代理结果&#xff0c;设置响应头&#xff08;请求头设置未生效&#xff0c;也可以在响应头上看&#xff09;。 2. …

PRL:新型量子传感方案突破纳米测量极限

朴茨茅斯大学的研究人员近期宣布了一项令人振奋的量子传感方案&#xff0c;该方案在测量两个干涉光子之间的横向位移方面达到了前所未有的量子灵敏度。 这一技术的突破为超分辨率成像技术带来了新的可能性。目前&#xff0c;这些技术通常采用单光子源作为探针&#xff0c;用于在…

LCD驱动IC-抗干扰液晶段码显示屏驱动芯片,液晶显示驱动原厂-VK2C23A/B LQFP64/48

产品品牌&#xff1a;永嘉微电/VINKA 产品型号&#xff1a;VK2C23A/B 封装形式&#xff1a;LQFP64/48 概述 VK2C23是一个点阵式存储映射的LCD驱动器&#xff0c;可支持最大224点&#xff08;56SEGx4COM&#xff09; 或者最大416点&#xff08;52SEGx8COM&#xff09;的LCD屏。…

电-热耦合市场联合出清!考虑均衡约束的综合能源系统电-热分配方法程序代码!

前言 随着现代城市面临环境问题&#xff0c;原来燃煤的水和空间供暖设备已逐渐被电锅炉和热泵等电气设备所取代。此外&#xff0c;集中生产热能并通过管网分配热能的区域供暖系统&#xff0c;由于其更高的效率&#xff0c;在冬季漫长寒冷的国家和地区越来越受欢迎。供暖设备的…

Windows电脑搭建HarmonyOS NEXTDeveloper Preview2环境详解

Windows电脑搭建HarmonyOS NEXTDeveloper Preview2环境详解&#xff1a; HarmonyOS NEXT Preview系列教程基于Api11讲解-IT营大地老师 1 、电脑要求以及注意事项 操作系统 &#xff1a; Windows10 64 位、 Windows11 64 位 内存 &#xff1a; 8GB 及以上&#xff0c;推荐 16G…

传闻不断!TCL紧急澄清 | 百能云芯

TCL科技5月7日晚间发布澄清公告称&#xff0c;近日关注到有媒体发布《TCL华星年内投630亿元加入8代oled线竞逐&#xff01;》《TCL华星计划年内投资第八代OLED》等相关报道。公司目前无新建8代或8.6代OLED产线的投资计划&#xff0c;公司不存在通过定增募集资金新建显示产线的计…

启英泰伦“离线自然说”技术,让智能语音芯片更善解人意

“以科技创新推动产业创新&#xff0c;特别是以颠覆性技术和前沿技术催生新产业、新模式、新动能&#xff0c;发展新质生产力”。2023年12月&#xff0c;中央经济工作会议强调了发展新质生产力的路径。“科技创新是发展新质生产力的核心要素&#xff0c;这也是我们一直潜心在做…

spring模块(六)spring监听器(2)@EventListener

一、介绍 监听器的简化写法 二、原理 三、使用 Slf4j Component public class MyTask {EventListenerpublic void onApplicationEvent(ApplicationEvent event) {if (event instanceof ContextRefreshedEvent) {log.info("监听到 ContextRefreshedEvent...");}if…

牛客题-链表内区间反转

链表内区间反转 这是代码 typedef struct ListNode listnode; struct ListNode* reverseBetween(struct ListNode* head, int m, int n ) {if (head NULL) {return NULL;}listnode* findhead head;listnode* findtail head;listnode* prev NULL;int count1 m;int count2…

基于Springboot的校园招聘系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的校园招聘系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…
最新文章