我有一个类型的枚举类,并且需要一个"to_string"函数来输出类型名称,所以我在自己的名称空间中编写了它。问题是,该命名空间中的其他函数试图调用to_string,例如,int(实际上只是int,不打算成为enum的一部分)正在查找自定义to_string并给出关于枚举初始化无效的错误。
我知道我可以显式地调用std::to_string而不是to_string,但我认为有更好的方法。我做错了什么?
下面是示例代码:
#include <iostream>
#include <string>
namespace other {
enum class Type {
Type1,
Type2
};
std::string to_string(const Type& type) {
switch(type) {
case Type::Type1:
return "Type1";
break;
case Type::Type2:
return "Type2";
break;
default:
{}
}
return "Unknown";
}
void run() {
using namespace std;
cout << string("Type: ") + to_string(Type::Type1) << endl;
cout << string("int: " ) + to_string(42) << endl; // this one generates compile-time errors
}
}
int main() {
other::run();
using namespace std;
cout << string("int: " ) + to_string(42) << endl; // This one is ok
return 0;
}
您需要显式指定要将什么函数引入"重载集" (参见wandbox示例):
void run() {
using namespace std;
using std::to_string;
cout << string("Type: ") + to_string(Type::Type1) << endl;
cout << string("int: " ) + to_string(42) << endl;
}
原因是ADL忽略了using指令。请参阅 3.4.2 [basic.lookup.argdep] :
当考虑关联的命名空间时,查找与将关联的命名空间用作限定符(3.4.3.2)时执行的查找相同,除了:-关联命名空间中的任何using指令都会被忽略。
在这个问题中有更详细的信息
这是一个棘手的情况,涉及到名称空间的一些微妙规则。让我们考虑一个更简单的例子:
namespace b {
void f(int) { }
}
namespace a {
using namespace b;
void f(char) { }
void g()
{
f(5); // calls f(char)
}
}
这里的问题是,即使我们有using namespace b
, b中的声明也被视为在公共命名空间(全局)中声明的,用于查找:
(c++ 14 7.3.4/2)
using-directive指定指定的命名空间中的名字可以在指定的作用域中使用Using-directive出现在Using-directive之后。在非限定名称查找(3.4.1)期间,会出现这些名称就好像它们是在最近的封闭命名空间中声明的,该命名空间包含using指令和指定名称空间。[注:在本文中,"contains"意为"直接或间接包含"。- - -结束注意]
因此,出于查找的目的,名称空间b中的名称被视为全局名称空间中的名称。这意味着命名空间a中的f(char)
将隐藏命名空间b中的f(int)
:
(c++ 14 3.3.10/4)
在查找由名称空间名称限定的名称期间,否则将进行的声明在using指令中可见的可以被同名的声明隐藏使用指示;见(3.4.3.2)。
在您的示例中,调用other::run()
中的to_string(42)
将找到other::to_string
,因为std::to_string(int)
是隐藏的。