结构的通用比较运算符

时间:2019-07-17 08:01:21

标签: c++ c++17 stdtuple

在许多单元测试中,我需要比较仅具有数据成员的简单结构的内容:

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::tuple,每个结构都可以轻松地转换为std::make_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;
}

但是,不幸的是,它只是无法编译,我真的不知道为什么。 lang告诉我:

main.cpp:11:18: error: use of overloaded operator '==' is ambiguous (with operand types
      'std::tuple<Object>' and 'std::tuple<Object>')
        return leftTuple==rightTuple;

我可以解决此编译错误以获得所需的行为吗?

1 个答案:

答案 0 :(得分:8)

否,由于比较元组会还原为比较元组的元素,因此leftTuple == rightTuple试图比较两个Object,这是不可能的。

  

借助std::tuple

,每个结构都可以轻松转换为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生成正确的比较运算符。