重载命名空间函数存在时需要std :: qualifier吗?

use*_*401 5 c++ name-lookup c++11

如果我有一些代码,如:

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()
    }
}
Run Code Online (Sandbox Code Playgroud)

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

我发现解决这个问题的一种方法是sqrt(vector<float>)std命名空间中定义但是感觉不对,这个问题的答案表明重载std是非法的.可能不是那么回事......

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

谢谢.

qua*_*dev 9

在C++中,名称查找不关心参数类型,只有名称很重要.当编译器查找名为的函数时sqrt,它将始终首先找到您的版本(因为查找以封闭的命名空间开始),然后停在那里.

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

namespace myNamespace
{
  using std::sqrt
  ...
}
Run Code Online (Sandbox Code Playgroud)

然后,将发生标准重载分辨率以区分您sqrtstd::sqrt,并将选择sqrt要调用的正确函数.

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


笔记:

  • 正如简单,指出参数依赖查找(ADL) ,使std::sqrt可用于在第一种情况下名称查找(因为vectorstd::),但它不会改变你所面临的问题.

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

  • 它确实关心参数类型.在第一次调用`sqrt`时,编译器将通过ADL找到`myNamespace :: sqrt`和`std :: sqrt`(因为`vector`在`std`中).它只选择`myNamespace :: sqrt`,因为它是一个更好的匹配. (2认同)