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

时间:2014-11-19 15:02:35

标签: c++ c++11 name-lookup

如果我有一些代码:

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()
    }
}

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

我发现解决此问题的一种方法是在sqrt(vector<float>)命名空间中定义std,但是感觉不对,this question的答案建议std中的重载1}}是非法的。可能不是那么回事......

如何重载sqrt(或任何其他标准库cmath函数),以便我不必总是限定使用哪一个并根据传递的顺序选择编译器功能参数?

感谢。

2 个答案:

答案 0 :(得分:9)

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

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

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

然后,将使用标准重载分辨率来区分您的sqrtstd::sqrt,并选择要调用的正确sqrt函数。

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


备注:

  • 正如Simple所指出的,Argument Dependent Lookup (ADL)使std::sqrt可用于第一种情况下的名称查找(因为vector位于std::),但它没有#39; t改变你所面临的问题。

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

答案 1 :(得分:3)

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

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

然后编译器将在sqrt

中选择适当的std::cout << sqrt( myFloat )