命名空间对C++模板推导优先级的影响

Impact of namespaces on C++ template deduction priority

在尝试实现元功能时,只有当某些类型存在“abs”功能时才需要存在,我 运行 遇到以下问题:

这里有两个代码示例,我希望产生相同的结果,但实际上它们不会:

第一个例子

#include <iostream>
#include <cmath>

using namespace std;

struct Bar{};

template<typename T>
int abs(T& v)
{
   return -1;
}

void test()
{
   Bar b;
   double x = -2;
   cout << abs(x) << endl;
   cout << abs(b) << endl;
}

int main()
{
    test();
} 

产量:

2
-1

这是我所期望的

第二个例子

#include <iostream>
#include <cmath>

namespace Foo
{
   struct Bar{};

   using namespace std;
    
   template<typename T>
   int abs(T& v)
   {
       return -1;
   }

   void test()
   {
    Bar b;
    double x = -2;
    cout << abs(x) << endl;
    cout << abs(b) << endl;
   }
}

int main()
{
    Foo::test();
} 

产量:

-1
-1

为什么在这里使用命名空间会使编译器优先于“本地”abs 方法 std::abs?

在第二种情况下,using 指令将声明的名称放置在全局名称空间中的指定名称空间中,以进行非限定名称查找。因此,在命名空间 Foo 中,找到了在此命名空间中声明的非限定名称 abs。即在命名空间Foo中声明的名称abs隐藏了在全局命名空间中声明的名称abs

来自 C++ 14 标准(7.3.4 Using 指令)

2 A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive. During unqualified name lookup (3.4.1), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace. [ Note: In this context, “contains” means “contains directly or indirectly”. — end note ]

第二个程序中最近的封闭命名空间是全局命名空间。

下面还有两个程序演示了使用 using 指令时非限定名称查找的相同原理。

#include <iostream>

void s() { std::cout << "The function s() called.\n"; }

struct s
{
    s() { std::cout << "The constructor of struct s called.\n"; }
};

void test()
{
    s();
}

int main()
{
    test();
}

程序输出为

The function s() called.

在此演示程序中,函数 s 的声明隐藏了结构 s 的声明。

第二个节目。

#include <iostream>

namespace N1
{
    void s() { std::cout << "The function N1::s() called.\n"; }
}

namespace N2
{
    using namespace N1;

    struct s
    {
        s() { std::cout << "The constructor of struct N2::s called.\n"; }
    };

    void test()
    {
        s();
    }
}

int main()
{
    N2::test();
}

程序输出为

The constructor of struct N2::s called.

在这种情况下,名称为 s 的结构声明隐藏了同名函数 s,由于 using 指令,其声明被放置在全局命名空间中。

为什么会出现这种情况可以参考Vlad的回答。但是,如果您仍然希望能够执行测试,则可以在单独的命名空间中进行测试。

#include <iostream>
#include <cmath>

namespace Foo
{   
   template<typename T>
   int abs(T& v)
   {
       return -1;
   }
}

namespace Test
{
    struct Bar{};
    using namespace std;
    using namespace Foo;
    void test()
    {
       Bar b;
       double x = -2;
       cout << abs(x) << endl;
       cout << abs(b) << endl;
    }
}

int main()
{
    Test::test();
} 

输出为

2
-1