将 C++ 数学函数扩展到非基本类型

extending c++ math functions to non fundamental types

我要延期?或重载?(不太确定如何称呼它)double 和其他基本类型使用的 sqrt() 函数,因此它可以由我自己使用 class。这里叫"myType"。当它的参数是 myType 时,我将编写函数 sqrt() 的代码。我希望 sqrt() 在用于基本类型时保持完整。这样我就可以编写一个涵盖这两种情况的模板。

例如。下面的关键是能够对基础和 myType 使用 bar()。 myType 不是 foo() ,基本类型不是 bar() 。这可以干净地完成吗?在此先感谢您的帮助。

#include <math.h>

using namespace std;

class myType
{
public:
    myType() {
    }
    double sqrt()
    {
        return  4;//just to return something
    }
};

template<typename T> bool bar(T in)
{
    if (sqrt(in) == 4) {// handels int and all sorts of other types but not my type
        return true;
    }
    return false;
}

template<typename T> bool foo(T in)
{
    if (in.sqrt() == 4) { //handles myType
        return true;
    }
    return false;
}

int main() {
    double y = 3;
    bar(y);//This is great

    myType x;
    //bar(x);//this is the line I want to write
    foo(x);//stuck doing this
}

我认为您无法做任何事情来使 std::sqrt 使用您的用户定义类型(除非可以使用转换运算符将它们转换为基本数据类型)。但是您可以编写自己的默认重定向到 std::sqrt 的函数,并将其专门用于您的用户定义类型。然后在您的代码中使用该函数而不是 std::sqrt.

首先,有参数依赖查找(ADL,a.k.a。König Lookup)在其参数的命名空间中搜索函数 foo()。因此,如果您在命名空间 my 中定义 class,您可以在该命名空间中定义一个函数 sqrt(),即使在非限定上下文中调用它也会自动找到它。

其次,为了使您的模板函数通用,您需要启用ADL。但是,如果您将它与基本类型一起使用,它仍然不会在命名空间 std 内部查找。因此,给编译器一个提示,函数中可能使用std::sqrt

示例(草图):

namespace my {
    struct number;
    number sqrt(number const&);
}

template<typename scalar>
scalar
sym_sqrt(scalar const& s) {
    using std::sqrt;
    if (s < 0) {
        return -sqrt(-s);
    else
        return sqrt(s);
}

int main() {
    float m = ...;
    std::cout << sym_sqrt(m);

    my::number n = ...;
    std::cout << sym_sqrt(n);
}

备注

  • 我没有using namespace std;。这既不是必需的,尤其是您 class 的用户也不需要这样做。现在改掉这个习惯!
  • 关于措辞,您不能扩展函数,而是在现有重载的基础上添加重载。
  • 如果您使用古老的编译器,您可能会遇到 sqrt 作为宏的问题。那就升级编译器吧
  • 请注意,您尝试中的 sqrt() 被定义为成员函数,这是一个完全不同的野兽。将其保留为与现有版本类似的免费功能。一般情况下,不要盲目的把东西放到classes。使用普通函数有充分的理由。特别是在数学意义上表示函数(没有副作用,没有外部依赖性)的数学函数实际上很好地放入了函数中。
  • std::sqrt() 已经为非基本类型重载,即对于不同的 std::complex<T> 类型。
  • if (X) {return true;} else {return false}; 可以写得更小如 return X;.