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

Make my struct or class compatible with std::round

鉴于以下情况,我如何使我的 class 或结构与 std::round 兼容? (我假设同样的事情也会使它与 std::floorstd::ceil 一起使用)。我可以这样做吗?

C++ Shell version

#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;
}

如果你想要一个函数来舍入你的 Rectangle 和 return 的所有点,那么你自己写一个;尝试为此使用 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();

你不能让 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 会为您找到它。


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

供讨论和思考:

我最初的想法是按照@Useless 的思路提供一个答案:- 在与参数相同的名称空间中的自由函数是执行此操作的正确方法。

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

round 听起来更像是命令而不是修饰符。我知道已经有一个 std::round 那个 returns 一个整数参数的副本,但是还有一个 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;
}