5

如果我有一些代码,例如:

using namespace std;

namespace myNamespace
{
    vector<float> sqrt( vector<float> v ) { return v; }

    void func()
    {
        vector<float> myVec = { 1, 2, 3, 4 };
        std::cout << sqrt( myVec )[0] << std::endl;
        float myFloat = 4.0f;
        std::cout << sqrt( myFloat ) << std::endl; // need to use std::sqrt()
    }
}

那么除非我将标记的行更改为 use ,否则它将无法编译std::sqrt。为什么?我知道如果我尝试重新定义sqrt(float),那么如果我想要使用标准库版本,myNamespace我就必须符合条件。std::编译器似乎试图转换myFloat而不是仅仅使用另一个 ( std) 命名空间中的函数。

我发现解决这个问题的一种方法是sqrt(vector<float>)std命名空间中定义,但这感觉不太对,对这个问题的回答表明重载std是非法的。那时应该不会走的路……

我怎样才能重载sqrt(或任何其他标准库 cmath 函数,就此而言),以便我不必总是限定要使用哪个并让编译器根据传递的函数参数进行选择?

谢谢。

4

2 回答 2

9

在 C++ 中,名称查找不关心参数类型,只关心名称。当编译器查找名为 的函数sqrt时,它总是会首先找到您的版本(因为查找从封闭的命名空间开始),然后停在那里。

您必须通过命名空间中的指令将名称从std::范围内引入来帮助编译器:using

namespace myNamespace
{
  using std::sqrt
  ...
}

然后,将进行标准重载决议以区分您的sqrtand std::sqrt,并选择sqrt要调用的正确函数。

为避免任何歧义,您应该始终限定名称(std::sqrtmyNamespace::sqrt


笔记:

  • 正如 Simple 所指出的,Argument Dependent Lookup (ADL)std::sqrt在第一种情况下可用于名称查找(因为is vectorin std::),但它不会改变您面临的问题。

  • 声明自己的sqrt函数std::是一个非常糟糕的主意(标准禁止,模板专业化除外)

于 2014-11-19T15:10:01.843 回答
3

您可以std::sqrt通过以下语句将其带入您的命名using std::sqrt;空间myNamespace

namespace myNamespace
{
    vector<float> sqrt( vector<float> v ) { return v; }
    using std::sqrt;
    ...

然后编译器会选择合适sqrtstd::cout << sqrt( myFloat )

于 2014-11-19T15:06:32.333 回答