结构的通用比较运算符
Generic comparison operator for structs
在我的许多单元测试中,我需要比较只有数据成员的简单结构的内容:
struct Object {
int start;
int stop;
std::string message;
}
现在,如果我想写这样的东西:
CHECK(object1==object2);
我总是要执行:
bool operator==(const Object& lhs, const Object& rhs) {
return lhs.start==rhs.start && lhs.stop==rhs.stop && lhs.message=rhs.message;
}
编写所有这些比较函数变得乏味,而且还容易出错。试想一下,如果我给Object添加了一个新的数据成员,但是比较运算符却没有更新,会发生什么。
然后我想起了我在 Haskell 和神奇的 deriving(Eq)
指令中的知识,它只是免费生成一个正常的比较函数。
我怎么能在 C++ 中推导出类似的东西?
令人高兴的是,我发现 C++17 带有泛型 operator==
,并且每个结构都应该可以通过 std::make_tuple
轻松转换为 std::tuple
。
所以我大胆尝试了以下:
#include <tuple>
#include <iostream>
#include <tuple>
template<typename T>
bool operator==(const T& lhs, const T& rhs)
{
auto leftTuple = std::make_tuple(lhs);
auto rightTuple = std::make_tuple(rhs);
return leftTuple==rightTuple;
}
struct Object
{
std::string s;
int i;
double d;
};
int main(int arg, char** args)
{
std::cout << (Object{ "H",1,2. } == Object{ "H",1,2. }) << std::endl;
std::cout << (Object{ "A",2,3. } == Object{ "H",1,2. }) << std::endl;
return EXIT_SUCCESS;
}
但是,不幸的是它无法编译,我真的不知道为什么。 Clang 告诉我:
main.cpp:11:18: error: use of overloaded operator '==' is ambiguous (with operand types
'std::tuple<Object>' and 'std::tuple<Object>')
return leftTuple==rightTuple;
我能否修复此编译错误以获得我想要的行为?
不,因为比较元组恢复到比较元组的元素,所以 leftTuple == rightTuple
尝试比较两个 Object
,这是不可能的。
that every struct should be easily convertible to an std::tuple
by the virtue of std::make_tuple
不,您只会得到一个 tuple
,其中包含一个元素,即结构。
诀窍是使用std::tie
:
std::tie(lhs.mem1, lhs.mem2) == std::tie(rhs.mem1, rhs.mem2)
但这与您原来的解决方案有同样的问题。不幸的是,C++17 没有任何工具来避免这个问题你可以写一个宏 :)。但是在 C++20 中你可以这样做:
struct Object
{
std::string s;
int i;
double d;
bool operator==(const Object &) const = default;
};
这将为 Object
.
生成正确的比较运算符
在我的许多单元测试中,我需要比较只有数据成员的简单结构的内容:
struct Object {
int start;
int stop;
std::string message;
}
现在,如果我想写这样的东西:
CHECK(object1==object2);
我总是要执行:
bool operator==(const Object& lhs, const Object& rhs) {
return lhs.start==rhs.start && lhs.stop==rhs.stop && lhs.message=rhs.message;
}
编写所有这些比较函数变得乏味,而且还容易出错。试想一下,如果我给Object添加了一个新的数据成员,但是比较运算符却没有更新,会发生什么。
然后我想起了我在 Haskell 和神奇的 deriving(Eq)
指令中的知识,它只是免费生成一个正常的比较函数。
我怎么能在 C++ 中推导出类似的东西?
令人高兴的是,我发现 C++17 带有泛型 operator==
,并且每个结构都应该可以通过 std::make_tuple
轻松转换为 std::tuple
。
所以我大胆尝试了以下:
#include <tuple>
#include <iostream>
#include <tuple>
template<typename T>
bool operator==(const T& lhs, const T& rhs)
{
auto leftTuple = std::make_tuple(lhs);
auto rightTuple = std::make_tuple(rhs);
return leftTuple==rightTuple;
}
struct Object
{
std::string s;
int i;
double d;
};
int main(int arg, char** args)
{
std::cout << (Object{ "H",1,2. } == Object{ "H",1,2. }) << std::endl;
std::cout << (Object{ "A",2,3. } == Object{ "H",1,2. }) << std::endl;
return EXIT_SUCCESS;
}
但是,不幸的是它无法编译,我真的不知道为什么。 Clang 告诉我:
main.cpp:11:18: error: use of overloaded operator '==' is ambiguous (with operand types
'std::tuple<Object>' and 'std::tuple<Object>')
return leftTuple==rightTuple;
我能否修复此编译错误以获得我想要的行为?
不,因为比较元组恢复到比较元组的元素,所以 leftTuple == rightTuple
尝试比较两个 Object
,这是不可能的。
that every struct should be easily convertible to an
std::tuple
by the virtue ofstd::make_tuple
不,您只会得到一个 tuple
,其中包含一个元素,即结构。
诀窍是使用std::tie
:
std::tie(lhs.mem1, lhs.mem2) == std::tie(rhs.mem1, rhs.mem2)
但这与您原来的解决方案有同样的问题。不幸的是,C++17 没有任何工具来避免这个问题你可以写一个宏 :)。但是在 C++20 中你可以这样做:
struct Object
{
std::string s;
int i;
double d;
bool operator==(const Object &) const = default;
};
这将为 Object
.