You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++20中能否为C结构体termios定义默认比较运算符?

问题:C++20中为C的termios结构体实现默认比较运算符失败

我想在C++20程序中使用C的termios结构体,需要比较两个termios实例。由于该结构体无默认比较逻辑,我尝试定义默认的==运算符:

bool operator == (const termios& lhs, const termios& rhs) = default;

但出现错误:

error: defaulted ‘bool operator==(const termios&, const termios&)’ is not a friend of ‘termios’

定义<=>运算符也失败:

auto operator <=> (const termios& lhs, const termios& rhs) = default;

错误信息相同,GCC 12.2和clang-14均出现该问题。我原本认为非成员比较运算符无需成为结构体友元(毕竟该结构体来自C头文件,所有成员均为公有),想询问是否存在无需逐成员比较的默认比较实现方式?


解答

问题核心在于C++20对默认ed比较运算符的规则限制:当你默认一个非成员的==或<=>运算符时,编译器要求该运算符必须是被比较类型的友元。这是因为默认ed的比较运算符会尝试遍历类型的所有成员(包括未来可能新增的私有成员)进行比较,语言规则通过强制友元身份来确保访问权限——哪怕当前类型的成员全是公有的。

由于termios是C标准库的结构体,我们无法修改它的定义添加友元声明,因此直接默认非成员比较运算符的方案不可行。不过有几种无需手动逐成员编写比较逻辑的替代方案:

方案1:利用std::tie实现自动逐成员比较

借助C++的std::tie将结构体成员打包成元组,利用元组默认支持的比较运算符间接实现结构体的比较,代码简洁且无需手动枚举所有成员:

#include <tuple>
#include <termios.h>

bool operator==(const termios& lhs, const termios& rhs) {
    return std::tie(lhs.c_iflag, lhs.c_oflag, lhs.c_cflag, lhs.c_lflag,
                    lhs.c_line, lhs.c_cc, lhs.c_ispeed, lhs.c_ospeed) ==
           std::tie(rhs.c_iflag, rhs.c_oflag, rhs.c_cflag, rhs.c_lflag,
                    rhs.c_line, rhs.c_cc, rhs.c_ispeed, rhs.c_ospeed);
}

auto operator<=>(const termios& lhs, const termios& rhs) {
    return std::tie(lhs.c_iflag, lhs.c_oflag, lhs.c_cflag, lhs.c_lflag,
                    lhs.c_line, lhs.c_cc, lhs.c_ispeed, lhs.c_ospeed) <=>
           std::tie(rhs.c_iflag, rhs.c_oflag, rhs.c_cflag, rhs.c_lflag,
                    rhs.c_line, rhs.c_cc, rhs.c_ispeed, rhs.c_ospeed);
}

方案2:创建C++包装类

封装一个持有termios的C++类,给包装类默认比较运算符,既保留对原始结构体的访问能力,又获得默认比较逻辑:

#include <termios.h>

class TermiosWrapper {
    termios t;
public:
    TermiosWrapper(const termios& t_) : t(t_) {}
    
    // 提供访问内部termios的接口
    const termios& get() const { return t; }
    termios& get() { return t; }

    // 默认比较运算符
    bool operator==(const TermiosWrapper&) const = default;
    auto operator<=>(const TermiosWrapper&) const = default;
};

方案3:使用std::memcmp(需谨慎)

由于termios是POD类型,理论上可以直接比较内存内容,但要注意结构体padding的问题:如果padding字节未被初始化,可能导致成员相同但内存比较结果不等。仅当能保证两个实例均被正确初始化(比如通过tcgetattr获取)时使用:

#include <cstring>
#include <termios.h>

bool operator==(const termios& lhs, const termios& rhs) {
    return std::memcmp(&lhs, &rhs, sizeof(termios)) == 0;
}

内容的提问来源于stack exchange,提问作者Nuclear

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 22:52:42