使我的结构或类与std::round兼容

Make my struct or class compatible with std::round

本文关键字:std round 兼容 我的 结构      更新时间:2023-10-16

给定以下内容,如何使我的类或结构与std::round兼容?(我认为同样的东西也会使它与std::floortd::ceil一起使用)。我能做这个吗?

C++外壳版本

#include <cmath>
struct Rectangle
{
    Rectangle(double _x1, double _x2, double _y1, double _y2) : 
        x1(_x1), y1(_y1), x2(_x2), y2(_y2) 
    {
    }
    double x1, y1, x2, y2;
};
int main(void )
{
    auto r = Rectangle(10.3, 10.4, 10.5, 10.6);
    r = std::round(r);
    std::cout << r.x1 << "," << r.y1 << "," << r.x2 << "," << r.y2 << std::endl;
}

不能让std::round这样做:它已经定义好了,也不能向命名空间std中添加新的重载。

可以编写一个新函数并使用它(一个简单的函数或Tartan Llama显示的方法,但我更喜欢这里的免费函数)

Rectangle round(Rectangle const &original) {
    return { std::round(original.x1), std::round(original.y1),
             std::round(original.x2), std::round(original.y2) };
}

同样,将此添加到命名空间std是非法的。只要确保它与Rectangle本身在同一个命名空间中,ADL就会为您找到它。


顺便说一句,让构造函数参数和它们对应的成员以不同的顺序排列在这里是令人困惑和容易出错的。在统一初始化和上面的显式构造函数之间切换需要更改参数顺序,但编译器无法发现这一点。

如果您想要一个函数来舍入Rectangle的所有点并返回一个新的点,那么您自己编写它;尝试使用std::round来实现这一点实际上没有意义。

一种选择:

struct Rectangle
{
    Rectangle(double _x1, double _x2, double _y1, double _y2) : 
      x1(_x1), y1(_y1), x2(_x2), y2(_y2) 
    { }
    Rectangle round() {
        return { std::round(x1), std::round(x2), 
                 std::round(y1), std::round(y2) };   
    }
    double x1, y1, x2, y2;
};

那就这样称呼它吧:

r = r.round();

用于讨论和思考:

我最初的想法是按照@Useless:-在与参数相同的命名空间中使用一个自由函数是正确的方法。

然而,更仔细地思考函数round的推断语义给我提出了一个问题:

round听起来更像是一个命令,而不是一个修饰符。我知道已经有一个std::round返回一个整型参数的副本,但还有一个std::sort对对象进行适当排序。

在我看来,如果你想要一个四舍五入的副本,你可能想调用一个名为rounded的函数,如果你想真正让一个对象自己四舍五舍五入,你可能想要调用它的round

如果你同意这个想法,代码会开始看起来像这样:

#include <cmath>
#include <iostream>
struct Rectangle
{
    Rectangle(double _x1, double _x2, double _y1, double _y2) 
    : x1(_x1), y1(_y1), x2(_x2), y2(_y2) 
    {
    }
    Rectangle& round() {
      using std::round;
      x1 = round(x1);
      y1 = round(y1);
      x2 = round(x2);
      y2 = round(y2);
      return *this;
    }
  Rectangle& normalise()
  {
    // something here
    return *this;
  }
    double x1, y1, x2, y2;
};
Rectangle rounded(Rectangle r)
{
  return r.round();
}
Rectangle& round(Rectangle& r)
{
  return r.round();
}
Rectangle normalised(Rectangle r)
{
  return r.normalise();
}
Rectangle& normalise(Rectangle& r)
{
  return r.normalise();
}
int main(void )
{
    auto r = Rectangle(10.3, 10.4, 10.5, 10.6);
  // take a rounded, normalised copy
  auto r1 = rounded(normalised(r));
  // take a rounded copy
  auto r2 = rounded(r);
  // take a copy
  auto r3 = r;
  // normalise and round the copy
  normalise(round(r3));
  round(r);
  std::cout << r.x1 << "," << r.y1 << "," << r.x2 << "," << r.y2 << std::endl;
}