提问人:J.M 提问时间:1/14/2022 最后编辑:Vlad from MoscowJ.M 更新时间:1/14/2022 访问量:113
命名空间对 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
abs
Foo
abs
来自 C++ 14 标准(7.3.4 Using 指令)
2 using 指令指定 namespace 可用于 using 指令的作用域 出现在 using 指令之后。在非限定名称查找期间 (3.4.1),名称看起来好像是用最近的 enclosed 命名空间,其中包含 using 指令和 Nominated 命名空间。[注:在此上下文中,“包含”是指 “直接或间接包含”。——尾注 ]
第二个程序中最接近的封闭命名空间是全局命名空间。
下面还有两个程序,它们演示了在使用 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.
在这种情况下,具有名称的结构的声明隐藏了具有相同名称的函数,该函数的声明由于 using 指令而被放置在全局命名空间中。s
s
至于发生这种情况的原因,你可以参考弗拉德的回答。但是,如果仍希望能够执行测试,则可以在单独的命名空间中执行测试。
#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
评论