【发布时间】:2021-05-08 20:02:54
【问题描述】:
据我所知,嵌套范围内的名称将在封闭范围内隐藏相同的名称,如下所示:
namespace ttt {
class A {};
void test(const A&, int)
{
cout << "ttt::test()" << endl;
}
}
void test(const ttt::A&, int)
{
cout << "global::test()" << endl;
}
int main()
{
void test(const ttt::A&, int);
ttt::A a;
test(a, 1);
}
主函数中void test(const ttt::A&, int); 的声明隐藏了与命名空间ttt 中相同的名称,因此控制台打印global::test()(在Visual Studio 2019 中测试)
但是,当我尝试下面的代码时:
std::ostream& operator<< (std::ostream& os, const string& str)
{
os << "global::operator" << endl;
return os;
}
int main()
{
std::ostream& operator<< (std::ostream & os, const string & str);
string a = "STD's operator";
cout << a << "STD's operator" << endl;
}
我尝试用我自己的<< 版本重载<< 运算符,它是在STL 中定义的模板。根据第一个例子,main中operator<<的声明应该隐藏<<的STL定义版本,那么期望的输出应该是
global::operator
global::operator
global::operator
或者编译错误,因为我不知道endl是否可以转换为string。
但是,程序的结果是:
global::operator
STD's operator
所以cout << a << "STD's operator" << endl; 语句中的第二个也是最后一个<< 调用了STL 的<<,而不是我定义的重载。 << 不应该已经被 main 中的声明 std::ostream& operator<< (std::ostream & os, const string & str); 隐藏了吗?
有人可能会说"STD's operator" 是const char*,因此Argument Dependent Lookup(ADL) 从std 命名空间添加了一个更好的候选对象std::ostream& operator<< (std::ostream&, const char*)。如果这是真的,那么如何解释第一个例子。第一个示例中的 ADL 过程可能会将 ttt::test(const A&, int) 添加到重载候选中,这会导致第一个示例中的歧义,但这并没有发生,ttt::test(const A&, int) 只是被隐藏了。
“C++ Primer 5th”的第 798 页说“当我们将类类型的对象传递给函数时,编译器会搜索定义参数类的命名空间除了正常范围查找”。我认为我的困惑是关于除了的准确含义。
如果这意味着类的命名空间与调用函数的范围具有相同的优先级,那么第一个示例应该会引起歧义。
如果这意味着该类的命名空间具有较低的优先级,那么第二个示例中main函数中的所有<<应该被我定义的版本隐藏。
如果这意味着类的命名空间具有更高的优先级,那么第一个示例应该打印"ttt::test()"。
那么发生了什么?
【问题讨论】:
-
"STD's operator"不是std::string,而是const char[N]。 -
@NathanOliver 嘿家伙,我更新了我的问题。
-
完整阅读一本 C++ 教科书,不要在第 3 章之后停下来。
标签: c++ c++11 namespaces