为什么我不能将此运算符重载在与结构相同的命名空间中?

for*_*818 6 c++ operator-overloading ostream

我有以下代码:

#include <iostream>
#include <vector>
namespace X {
    std::ostream& operator<<(std::ostream& os,const std::vector<double>& v){
        for (int i=0;i<v.size();i++){os << v[i] << " ";}
        return os;
    }
    namespace Y {
        struct A {std::vector<double> x;};    
        std::ostream& operator<<(std::ostream& os,const A& a){
            os << a.x << std::endl;
            return os;
        }
   }     
}

using namespace X;

int main(int argc, char** argv) {
   std::vector<double> v(10,0);
   std::cout << v << std::endl;
   Y::A a;
   std::cout << a << std::endl;
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

第一个重载是有效的,但第二个没有.由于某种原因,它找不到第一个.我收到错误:

no match for 'operator<<' (operand types are 'std::ostream 
{aka std::basic_ostream<char>}' and 'const std::vector<double>')
     os << a.x << std::endl;
        ^
Run Code Online (Sandbox Code Playgroud)

我不明白为什么我会收到这个错误.例如,像这样的东西似乎是完全有效的:

namespace A {
    void foo(){}
    namespace B {
        void bar(){foo();}
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,修复上述问题的唯一方法是将第二个重载也放在X中.为什么不能将它与结构(即X :: Y)放在同一个命名空间中?

PS:我正在阅读ADL并且我发现了一些相关的问题(例如这个这个,但是我从阅读本文中理解的,上面应该有效.

Mat*_*jek 2

在参数相关查找(或 Koenig 查找)中,编译器将每个参数的父作用域中声明的所有符号添加到可见范围。

即使Y是 的“子命名空间” X,它们在 方面也不相关ADL。第一个参数是在std::命名空间中定义的类型,而第二个参数是本地符号(在与函数本身相同的命名空间中定义)。

请注意,由于上述原因,您很可能会在此行中收到另一个错误:

std::cout << v << std::endl;
Run Code Online (Sandbox Code Playgroud)

当编译器将无法找到operator<<重载的 for std::vector<double>(因为它位于内部namespace X)。

为了解决这个问题,您可以使用:

using X::operator<<
Run Code Online (Sandbox Code Playgroud)

内部namespace Y或移动该过载。

如果您想知道为什么foobar示例有效:那是因为ADL参数依赖查找)是关于函数参数的范围,而不是函数本身。在foobar代码中,ADL不适用。