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

