在C++中是否可以重载abs()函数?

3
我正在编写一个处理二维矩阵代数的库,使用模板来定义矩阵内部数据的类型,以便能够自由地处理各种类型的矩阵数据。
我想知道是否有办法重载abs()函数,以便将矩阵的行列式写成abs(M);,或者我必须为此使用另一个名称。我唯一的担心是矩阵的行列式与其绝对值有关(正如标准符号所示),所以在我看来,重载绝对值函数以返回行列式是有意义的。
我已经尝试将其作为类方法,并使用m.abs();进行调用,显然这样做效果很好...但我希望该函数位于类之外,并将矩阵作为参数传递,就像int abs(int n);函数一样。因此,我尝试只是重载函数,但这给我带来了一些问题,因为abs(n);函数期望一个整数或长整数值作为参数,而不是用户定义的矩阵。我还尝试将其设置为类的友元方法,但似乎没有帮助。期待您的建议。

4
所以,我试图只是过载函数,这给我带来了一些问题....除非您向我们展示代码和错误消息,否则我们无法知道您所说的“问题”是什么。请阅读有关[mcve]的内容。 - 463035818_is_not_an_ai
8
大多数人会期望abs()函数返回一个正值。然而,一般的矩阵行列式可以是正数或负数。另一方面,我认为大多数用户会理解det(M)应该做什么。 - lastchance
4
在我看来,将绝对值函数重载为返回行列式是有道理的。而不是因为“有道理”而改变名称,可以使用正确的名称来称呼计算行列式的函数,比如determinant。不要为了重载而重载,当不同的重载执行不同的操作时,这样做会带来更多的伤害而不是好处。 - 463035818_is_not_an_ai
2
对于 @paddy 的小补充。你不应该重载 std::abs 或者在命名空间 std 中编写函数,也不应该在全局范围内编写函数。相反,你应该创建一个新的命名空间,比如 Matrix,然后在其中编写一个名为 abs 或者 det 的函数。 - LiuYuan
4
矩阵的行列式与绝对值概念无关。(“行列式竖线”与“绝对值竖线”不是同一个符号。)请参阅例如此文章了解有关符号的说明。 - molbdnilo
显示剩余10条评论
2个回答

7

C++有一个名为参数依赖查找的特性,旨在处理类似这样的情况,即您想在自由函数之间进行重载。典型的应用是重载std::swap,但您也可以在这里使用它。

#include <cmath>
// using std::abs
#include <iostream>

namespace my_ns {

class Matrix
{};

float abs(const Matrix&)
{
    std::cout << "Calling abs(Matrix)\n";
    return 0.f;
}

} /* namespace my_ns */

int main()
{
    my_ns::Matrix mat;
    std::cout << abs(mat) << '\n';
}

输出:

Calling abs(Matrix)
0

关键点是在调用 `abs` 时不需要指定命名空间。如果调用 `std::abs(mat)`,它会失败。然而,如果使用 `using std::abs` 命令,它仍然有效。这对于模板很有用,因为你可以在标准类型中使用 `std::abs`,同时也可以在自己的命名空间中使用自定义的 `abs`。
template<class T>
auto call_abs(const T& value)
{
    using std::abs;
    return abs(value);
}

1
可以在C++中重载abs()函数吗?
是的,虽然可以,但不建议这样做。原因如下:
1. abs()函数已经在std命名空间中定义,它是标准库的一部分。你应该在自己的另一个命名空间中编写自己的函数,比如Matrix。
2. abs()通常用于计算一个数的绝对值,这样的命名会引起混淆。
如果你仍然想这样做,你可以很容易地实现:
#include <cmath>

struct Matrix {};

int abs(const Matrix &m) { return 0; }

int main() {
  Matrix m;
  int det = abs(m);
}

以下是实现你的abs函数的一些可能方式(尽管我认为det可能是一个更好的名称):
// Matrix.h
namespace matrix {
class Matrix { /**/ };

int det(const Matrix&);
} // namespace matrix

或者:

class Matrix {
    static int det(const Matrix&);
};

应该是 int abs(const Matrix &m) - 463035818_is_not_an_ai
@463035818_is_not_an_ai 修改已完成 - LiuYuan
在命名空间 std 中像你所描述的那样重载函数会导致未定义行为。虽然有一些特定情况下是允许的,但你提供的情况不属于其中之一。请参考 https://en.cppreference.com/w/cpp/language/extending_std 获取相关信息。 - Peter
@Peter 非常感谢,我之前完全不知道这样的限制。那么我可以理解为,在命名空间 std 中,除非包含模板,否则我们不应该添加定义或声明,对吗? - LiuYuan
1
大致上来说,可以专门化标准库中的模板,但不能简单地向std添加新的模板函数或类,也不能(如你所做的)重载标准库中的函数。 - Peter
@Peter 我明白了。非常感谢。 - LiuYuan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接