Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >c++20默认比较运算符和空基类

c++20默认比较运算符和空基类
EN

Stack Overflow用户
提问于 2022-08-25 02:29:32
回答 3查看 150关注 0票数 3

c++20默认比较运算符是一个非常方便的特性。但是我发现如果这个类有一个空的基类,那么它就不太有用了。

默认的operator<=>通过依次比较T的基(从左到右深度-首先)和非静态成员(按声明顺序排列)来计算<=>,递归展开数组成员(按下标的顺序),并在发现不相等的结果时尽早停止。

根据标准,如果SComparable没有operator<=>,那么base就不会有operator<=>。在我看来,为空类定义比较操作符是没有意义的。因此,默认的比较运算符不适用于具有空基类的类。

代码语言:javascript
运行
AI代码解释
复制
struct base {};

struct SComparable: base {
  int m_n;
  auto operator<=>(SComparable const&) const& = default; // default deleted, clang gives a warning
};

struct SNotComparable: base {
  int m_n;
};

如果我们迫切希望使用默认的比较运算符,并因此为空基类base定义比较运算符。另一个派生类SNotComparable由于其空基类base而变得可比较错误。

代码语言:javascript
运行
AI代码解释
复制
struct base {
  auto operator<=>(base const&) const& = default;
};

struct SComparable: base {
  int m_n;
  auto operator<=>(SComparable const&) const& = default;
};

struct SNotComparable: base { // SNotComparable is wrongly comparable!
  int m_n;
};

那么,对于基类为空的类使用默认比较运算符,推荐的解决方案是什么?

编辑:一些答案建议在空基类中添加默认的比较运算符,并在不可比较的派生类中显式删除比较运算符。

如果我们将默认比较运算符添加到一个非常常用的空基类中,那么突然间,它的所有不可比较的派生类都是可比较的(总是返回std::strong_ordering::equal)。我们必须找到所有这些派生的不可比较类,并显式删除它们的比较运算符。如果我们遗漏了某个类,以后想使它具有可比性,但忘记自定义它的比较操作符(我们都会出错),我们就会得到一个错误的结果,而不是像以前一样在空基中没有默认的比较操作符,而不是编译错误。那么,为什么首先使用默认的比较运算符?我想省去一些努力,而不是多介绍一些。

代码语言:javascript
运行
AI代码解释
复制
struct base {
  auto operator<=>(base const&) const& = default;
};

struct SComparable: base {
  int m_n;
  auto operator<=>(SComparable const&) const& = default;
};

struct SNotComparable1: base {
  int m_n;
  auto operator<=>(SNotComparable1 const&) const& = delete;
};

struct SNotComparableN: base {
  int m_n;
  // oops, forget to delete the comparison operator!
  // if later we want to make this class comparable but forget to customize comparison operator, we get a wrong result instead of a non-comparable compile error.
};
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-08-25 11:16:39

我想做一个基于@Barry's answer的小修改。我们可以有一个通用的混合类comparable<EmptyBase>,为任何空基提供类似的操作符。如果我们想对从空基类(Es)派生的类使用默认比较运算符,我们可以简单地从comparable<base>而不是base派生此类类。它也适用于链式空基comparable<base1<base2>>

代码语言:javascript
运行
AI代码解释
复制
struct base { /* ... */ };

template<typename EmptyBase>
struct comparable: EmptyBase {
    static_assert(std::is_empty<EmptyBase>::value);
    template<typename T> requires std::same_as<comparable>
    friend constexpr auto operator==(T const&, T const&)
        -> bool
    {
        return true;
    }

    template<typename T> requires std::same_as<comparable>
    friend constexpr auto operator<=>(T const&, T const&)
        -> std::strong_ordering
    {
        return std::strong_ordering::equal;
    }
};

struct SComparableDefault: comparable<base> {
  int m_n;
  auto operator<=>(SComparableDefault const&) const& = default;
};

struct SNotComparable: base {
  int m_n;
};

struct SComparableNotDefault: base {
  int m_n;
  constexpr bool operator==(SComparableNotDefault const& rhs) const& {
    /* user defined... */
  }
  constexpr auto operator<=>(SComparableNotDefault const& rhs) const& {
    /* user defined... */
  }
};
票数 1
EN

Stack Overflow用户

发布于 2022-08-25 07:02:58

在我看来,为空类定义比较操作符是没有意义的。

很明显这不是毫无意义的。如果要做的是默认类型的比较,那必然意味着比较所有类型的子对象,包括基类子对象,这要求它们是可比较的--即使它们是空的。

你需要做的是提供-只是有条件的。最简单的方法可能是提供一个不同的空基类:

代码语言:javascript
运行
AI代码解释
复制
struct base { /* ... */ };

struct comparable_base : base {
    friend constexpr auto operator==(comparable_base, comparable_base)
        -> bool
    {
        return true;
    }

    friend constexpr auto operator<=>(comparable_base, comparable_base)
        -> std::strong_ordering
    {
        return std::strong_ordering::equal;
    }
};

然后,当您想要进行比较时,从comparable_base继承,当不想进行比较时,继承base

代码语言:javascript
运行
AI代码解释
复制
struct SComparable: comparable_base {
  int m_n;
  auto operator<=>(SComparable const&) const& = default;
};

struct SNotComparable: base {
  int m_n;
};

我在那里使用隐藏的朋友比较,因为它是空的,所以我可以按值取类型。也很容易成为会员。

票数 2
EN

Stack Overflow用户

发布于 2022-08-25 03:31:27

对于带有空基类的类使用默认比较运算符的推荐解决方案是什么?

解决方案是将默认的比较器添加到基类中,然后在SComparable中执行您所做的事情,如果您希望在比较中包含SComparable的添加成员--就像使用成员的基类一样。

如果不希望它们包含在比较中,就不要像在SNotComparable中那样添加默认的比较器--而且基类比较器也将被使用--就像在带有成员的基类中一样。

如果您不希望SNotComparable中的基类行为并且不希望SNotComparable是可比较的,那么就像基类有成员时一样,delete是比较器:

代码语言:javascript
运行
AI代码解释
复制
auto operator<=>(SNotComparable const&) const& = delete;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73485942

复制
相关文章
STL 设计之 EBO(空基类优化)
本节从空类开始,到 STL 内部,到测试,再到我们自己实现一个 EBO,对比性能,最后再测试,总结。
公众号guangcity
2019/10/24
2.1K0
基类和派生类
  在面向对象设计中,被定义为包含所有实体共性的class类型,被称为“基类”。-百度百科
全栈程序员站长
2022/09/20
1K0
C++中的空类默认包含哪些类成员函数
空类 class Empty { } 空类包含的函数(6个) class Empty { public: Empty(); // 缺省构造函数// Empty( const Empty& ); // 拷贝构造函数// ~Empty(); // 析构函数// Empty& operator=( const Empty& ); // 赋值运算符// Empty* operator&(); // 取址运算符 const Empty* operator&() const; // 取址运算符 const };
全栈程序员站长
2021/04/07
1.6K0
基类View
在 Class-based views 源码解析 #1 中我们从宏观层面讨论了 Django 类视图的类继承结构以及命名规律。接下来我们要深入各个具体的类视图,探索其具体的代码实现。本节将分析 base.py 中最重要的的一个类,它也是所有类视图的基类 View 。 之前我们说过,尽管类视图看上去类的种类繁多,但每个类都是各司其职的,且从类的命名就可以很容易地看出这个类的功能。大致可分为如下三个大的功能块,分别由三个类提供对应的方法: 处理 HTTP 请求。根据 HTTP 请求方法的不同做出相应处理。例如同
追梦人物
2018/04/17
9130
Access比较和逻辑运算符
大家好,前面算术运算符的实例,本节介绍比较运算符和逻辑运算符。在查询设计的第三步条件设置中较常用。
无言之月
2020/04/08
1.7K0
Access比较和逻辑运算符
SQL的逻辑运算符和比较运算符
SQL是一种结构化查询语言,用于管理和操作关系型数据库。SQL中的逻辑运算符和比较运算符是进行数据筛选和比较的基础工具,本文将介绍SQL中常用的逻辑运算符和比较运算符,并给出示例进行说明。
玖叁叁
2023/04/11
1.1K0
JavaScript 比较 和 逻辑运算符
如果变量 age 中的值小于 18,则向变量 voteable 赋值 "年龄太小",否则赋值 "年龄已达到"。
程序狗
2021/09/16
3350
Python学习-比较运算符和逻辑运算符
  and  布尔"与" - --  如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值
py3study
2020/01/19
5890
C# 继承 基类和派生类基类的初始化C# 多重继承
继承是面向对象程序设计中最重要的概念之一。继承允许我们根据一个类来定义另一个类,这使得创建和维护应用程序变得更容易。同时也有利于重用代码和节省开发时间。
酱紫安
2020/07/24
4.6K0
解读C++即将迎来的重大更新(二):C++20的核心语言
之前的一篇博客概览式地介绍了 C++20 的概念、范围、协程和模块,下面开始介绍它的核心语言。
机器之心
2020/02/12
1.1K0
解读C++即将迎来的重大更新(二):C++20的核心语言
iOS中UITableView和UICollectionView的默认空态页
  项目中想实现空态页风格统一控制的效果,就封装了一个默认空态页,使用的技术点有:1 方法替换 ,2 给分类(Category)添加属性。   我们知道,扩展(extension)可以给类添加私有变量和方法。但是分类(Category)不可以,但是我们又想在原生的UITableView和UICollectionView上添加空态页,所以使用了黑科技runtime中提供的对象关联。objc_setAssociatedObject/objc_getAssociatedObject。   懒得说明了,具体看代码。
王大锤
2018/05/17
1K0
空值合并运算符(??)
使用空值合并运算符为常量提供默认值,保证常量不为 null 或者 undefined。
用户9914333
2022/12/14
1.4K0
空值合并运算符(??)
[PHP]实体类基类和序列化__sleep问题
1.构造函数传参 2.__get和__set实现,当调用不存在的属性的时候,可以取值和赋值到data属性数组 3.__sleep实现,当序列化对象的时候,只序列化data属性数组和类内初始化定义的字段 4.__isset实现,可以判断属性是否存在,通过判断data属性数组 5.toArray方法实现,返回data属性数组 6.记录了构造初始化后,动态添加的属性字段
唯一Chat
2019/09/10
5110
性能框架多线程基类和执行类--视频讲解
讲完了自动化测试的相关内容,接下来开喷性能测试了。首先分享了我的思路:通过一个继承Thread的基类(虚拟类)来规范一些通用的行为和功能,这一部分比较浅,然后通过两个虚拟类来实现两种不同压测模式(定量压测和定时压测),然后在这两个模式类(虚拟类)的基础上,去实现各种不同需求的多线程测试类。还有一个非常重要的就是执行类,通过多线程类来构造多线程任务,用执行类来执行,完事儿之后计算和保存相关测试数据(包括数据库存储和可视化)。
FunTester
2020/04/15
3300
mongoDB 比较运算符
比较运算符是我们学习任何语言或系统中最为常见的运算符之一。mongoDB的比较运算符,跟Linux的差不多,只不过每一个比较运算符前面会带有符号,他们分别是$eq、$gt、$gte、$lt、$lte、$ne、$in、符号,他们分别是\$eq、\$gt、\$gte、\$lt、\$lte、\$ne、\$in、nin等,下面将对这几个运算符进行描述。 一、比较运算符 $eq = "=" $gt (greater than ) > $gte
Leshami
2018/08/13
1.2K0
BaseMongo基类设计
为进一步完善框架应用,本次系列文章主要是介绍如何完善架构功能,以及如何应用架构做一些具体的应用开发。本系列课程可以在github上找到相应资源,具体每篇文章中都会提供链接。 本次介绍的主要是mongo基类的设计,以及应用。相关请查看文章下面链接下载http://5xpan.com/fs/7hueanfgd6h350fe4/(下载链接有收益,请原谅有广告)。 如果你嫌弃慢的话,也可以直接去github(https://github.com/tnodejs/BaseMongodb) 主要函数结构 私有方法
蛋未明
2018/06/07
1K0
C++20新特性—“宇宙飞船”运算符
三路运算符是由Herb Sutter提出,2019年10月8日确定的C++20草案中正式将三路运算符纳入进来。在类中使用三路运算符后,编译器可以默认生成6个基础运算符,这一新特性的使用从一定程度上来说减少了开发的工作量,因此也受到大家的喜爱,被大家称为:宇宙飞船运算符。
CPP开发前沿
2021/12/04
2.3K0
【mysql】比较运算符
比较运算符 = <=> <> != < <= > >= 比较运算符用来对表达式左边的操作数和右边的操作数进行比较,比较的结果为真则返回1,比较的结果为假则返回0,其他情况则返回NULL。 比较运算符经常被用来作为SELECT查询语句的条件来使用,返回符合条件的结果记录。 [请添加图片描述] [请添加图片描述]1. 等号运算符(=) 等号运算符(=)判断等号两边的值、字符串或表达式是否相等,如果相等则返回1,不相等则返回0。 在使用等号运算符时,遵循如下规则: 如果等号两边的值、字符串或表达式都
兮动人
2022/03/02
2.5K0
MVC的基类
设计一个验证用户身份是否登陆的基类BaseController /// <summary> /// 所有需要进行登录控制的控制器基类 /// </summary> public class BaseController : Controller { /// <summary> /// 当前登录的用户属性 /// </summary> public UserInfo CurrentUserInfo { get;
欢醉
2018/01/22
7880
Python比较运算符
#!/usr/bin/python # -*- coding: UTF-8 -*- a = 21 b = 10 c = 0 if a == b : print "1 - a 等于 b" else: print "1 - a 不等于 b" if a != b : print "2 - a 不等于 b" else: print "2 - a 等于 b" if a <> b : print "3 - a 不等于 b" else: print "3 - a 等于 b" if a < b : print "4 - a 小于 b" else: print "4 - a 大于等于 b" if a > b : print "5 - a 大于 b" else: print "5 - a 小于等于 b" # 修改变量 a 和 b 的值 a = 5 b = 20 if a <= b : print "6 - a 小于等于 b" else: print "6 - a 大于 b" if b >= a : print "7 - b 大于等于 a" else: print "7 - b 小于 a"
用户8442333
2021/05/26
5090

相似问题

是否可以在C++20中的类定义之外默认比较运算符?

125

默认相等运算符C++20

12

Dart:将派生类的比较运算符委托给基类的比较运算符

34

空基类

10

C++20显式默认的相等运算符

14
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文