如何实现C++聚合结构的(中)相等运算符?

发布于 2024-10-17 13:53:29 字数 643 浏览 1 评论 0原文

有时我有这样的结构 --

struct aggregate1 {
  std::string name;
  std::vector<ValueT> options;
  size_t foobar;
  // ...
};

-- 其中(内)相等简单地定义为所有成员的(内)相等: lhs_name == rhs_name && lhs_options == rhs_options && lhs_foobar == rhs_foobar

实现这一点的“最佳”方法是什么? (最好是:(运行时-)效率、可维护性、可读性)

  • operator==operator!= 而言
  • operator!= 而言operator==
  • ==!= 的单独实现
  • 作为成员函数还是作为自由函数?

请注意,这个问题仅涉及(内)相等操作,因为比较 (<, <=, ...) 对于这样的聚合体。

Sometimes I have structs such as this --

struct aggregate1 {
  std::string name;
  std::vector<ValueT> options;
  size_t foobar;
  // ...
};

-- where (in)equality is simply defined as (in)equality of all members: lhs_name == rhs_name && lhs_options == rhs_options && lhs_foobar == rhs_foobar.

What's the "best" way to implement this? (Best as in: (Runtime-)Efficiency, Maintainability, Readability)

  • operator== in terms of operator!=
  • operator!= in terms of operator==
  • Separate implementations for == and !=
  • As member or as free functions?

Note that this question is only about the (in)equality ops, as comparison (<, <=, ...) doesn't make too much sense for such aggregates.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

把昨日还给我 2024-10-24 13:53:29

我会这样做,但可能会将operator==定义移动到cpp文件中。将运算符!=保留为内联

记住首先比较最有可能不同的成员变量,以便其余的成员变量被短路并且性能更好。

struct aggregate1 {
  bool operator==(const aggregate1& rhs) const
  {
     return (name == rhs.name)
     && (options == rhs.options)
     && (foobar == rhs.foobar);
  }
  bool operator!=(const aggregate1& rhs) const
  {
    return !operator==(rhs);
  }

  std::string name;
  std::vector<ValueT> options;
  size_t foobar;

  // ...
};

I would do this but maybe move operator== definition to cpp file. Leave operator!= to be inline

Remember to compare member variables that are most likely to differ first so the rest are short-circuited and performance is better.

struct aggregate1 {
  bool operator==(const aggregate1& rhs) const
  {
     return (name == rhs.name)
     && (options == rhs.options)
     && (foobar == rhs.foobar);
  }
  bool operator!=(const aggregate1& rhs) const
  {
    return !operator==(rhs);
  }

  std::string name;
  std::vector<ValueT> options;
  size_t foobar;

  // ...
};
此生挚爱伱 2024-10-24 13:53:29

成员函数或自由函数是一个品味问题,在我看来,单独编写 ==!= 的实现似乎很无聊,而且容易出错(您可能会忘记一个成员)两个运算符之一,并且需要时间才能注意到),而不会在效率方面增加任何内容(调用另一个运算符并应用 ! 的成本可以忽略不计)。

该决定仅限于“用 operator!= 实现 operator== 更好还是相反?

在我看来,从可维护性/可读性/效率角度来看是一样的;为了保持一致性,我只建议在任何地方都以相同的方式进行操作,唯一需要使用其中一个作为“基本运算符”的情况是当您知道这一点时。 ,在结构中包含的类型中,该运算符比其否定更快,但我不知道什么时候会发生这种情况。

Member or free function is a matter of taste, and writing separate implementations of == and != seems to me boring, error-prone (you may forget a member in just one of the two operators, and it will take time to notice) without adding anything in terms of efficiency (calling the other operator and applying ! has a negligible cost).

The decision is restricted to "is it better to implement operator== in terms of operator!= or the contrary?

In my opinion, in terms of maintainability/readability/efficiency it's the same; I'd only recommend to do it in the same way everywhere for the sake of consistency. The only case where you'd want to prefer to use one or the other as the "base operator" is when you know that, in the types contained in your structure, that operator is faster than its negation, but I don't know when this could happen.

别挽留 2024-10-24 13:53:29

在 C++20 中,实现相等和不等运算符可以像将 operator== 声明为 default 一样简单:

struct S {
  int x;
  // ...

  // As member function
  bool operator==(S const &) const = default;
  
  // As non-member function (hidden friend)
  // friend bool operator==(S const &, S const &) = default;
};

如果只有 operator== 是假设,a!=b 根据重载解析被解释为 !(a==b),因此不需要为 运算符提供显式重载!=

我认为默认 operator== 作为隐藏友元更好,因为它适用于引用包装的对象:

S s;
auto rs{std::ref(s)};
rs==rs; // OK for hidden friend; ill-formed if declared as member function

在此示例中,operator== 没有为 std::reference_wrapper,但参数相关查找 (ADL) 可以选择隐藏友元,其操作数隐式转换为 S const &。但请注意,::operator==(rs,rs) 仅当 operator== 被定义为自由函数时才起作用,因为限定名称不会触发 ADL 。

In C++20, implementing equality and inequality operators can be as simple as declaring operator== as default:

struct S {
  int x;
  // ...

  // As member function
  bool operator==(S const &) const = default;
  
  // As non-member function (hidden friend)
  // friend bool operator==(S const &, S const &) = default;
};

If only operator== is provided, a!=b is interpreted as !(a==b) according to overload resolution, so there is no need for providing an explicit overload for operator!=.

I would argue that defaulting operator== as a hidden friend is preferable because it works with reference-wrapped objects:

S s;
auto rs{std::ref(s)};
rs==rs; // OK for hidden friend; ill-formed if declared as member function

In this example, operator== is not defined for std::reference_wrapper<S>, but argument-dependent lookup (ADL) can select the hidden friend with operands implicitly-converted to S const &. Notice, however, that ::operator==(rs,rs) will only work if operator== is defined as a free function because ADL is not triggered for qualified names.

多孤肩上扛 2024-10-24 13:53:29

恕我直言,以朋友的身份实现并实现 operator== (例如,某些 STL 算法将依赖于此),并且 operator!= 应实现为等于的否定操作员。

IMHO, implement as friends and implement the operator== (some STL algorithms will rely on this for example) and the operator!= should be implemented as the negation of the equals operator.

醉梦枕江山 2024-10-24 13:53:29

(-:自我回答:-)

我想强调聚合 WRT 效率的一个方面:

op==op!=< 的评估顺序/code> 与(平均)性能无关。

假设现在单独实现,并给出两个极端 (a-eq) 所有子元素相等和 (b-neq) 所有子元素不相等,我们有以下情况:

  • (a-eq) + operator== :需要比较所有子元素以返回 true
  • (a-eq) + operator!= :需要比较所有子元素以返回 false
  • ( b-neq) + operator== :确定第一个子元素不相等后返回 false
  • (b-neq) + operator!= :确定第一个子元素后返回 true不相等

由于无论哪种方式,平均性能都是相同的,至少对我来说,根据 op== 实现 op!= 似乎更自然,因为它我觉得实施平等行动更自然。

(-: Self answer :-)

I would like to highlight one aspect of aggregates WRT efficiency:

The order of evaluation of op== and op!= is irrelevant for (average) performance.

Assuming separate implementations for now and given the two extremes (a-eq) all subelements equal and (b-neq) all subelements inequal, we have these cases:

  • (a-eq) + operator== : Needs to compare all sub elements to return true
  • (a-eq) + operator!= : Needs to compare all sub elements to return false
  • (b-neq) + operator== : Returns false after 1st sub element is determined inequal
  • (b-neq) + operator!= : Returns true after 1st sub element is determined inequal

Since performance on average is the same either way it seems -- at least to me -- more natural to implement op!= in terms of op==, as it feels more natural to me to implement the equality op.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文