代码之家  ›  专栏  ›  技术社区  ›  arynaq

std::vector<t>的比较运算符找不到t的比较运算符

  •  13
  • arynaq  · 技术社区  · 8 年前

    以下非常简单的代码无法编译

    #include <vector>
    #include <string>
    
    
    namespace Foobar {
        struct Test {
            std::string f;
            std::uint16_t uuid;
        };
    }
    
    bool operator==(const Foobar::Test& lhs, const Foobar::Test& rhs){
        return lhs.f == rhs.f && lhs.uuid == rhs.uuid;
    }
    
    
    int main(){
    
        std::vector<Foobar::Test> a;
        std::vector<Foobar::Test> b;
    
        if(a==b){
    
        }
    
        return 0;
    }
    

    https://godbolt.org/g/zn6UgJ

    不会在我所有的编译器中编译。

    而下面

    #include <vector>
    #include <string>
    
    
    namespace Foobar {
        struct Test {
            std::string f;
            std::uint16_t uuid;
        };
    
        bool operator==(const Foobar::Test& lhs, const Foobar::Test& rhs){
            return lhs.f == rhs.f && lhs.uuid == rhs.uuid;
        }
    }
    
    
    
    int main(){
    
        std::vector<Foobar::Test> a;
        std::vector<Foobar::Test> b;
    
        if(a==b){
    
        }
    
        return 0;
    }
    

    https://godbolt.org/g/o4pc1b

    编译得很好,这让我觉得 std::vector<T> 比较运算符在的命名空间中查找 T ,为什么不考虑全局命名空间?

    1 回复  |  直到 8 年前
        1
  •  9
  •   Igor Tandetnik    8 年前

    普通的非限定名称查找开始在使用名称的上下文中查找,并沿着封闭作用域的链进行查找。它停在包含匹配名称的最嵌套作用域中。即使这样找到的名称后来被确定为不合适(例如,对于给定的调用,函数重载是不可行的;或者成员函数是不可访问的),这也是正确的。

    这里,查找的上下文是 std::operator==(vector, vector) ,所以它开始在命名空间中查找 std . 有很多超载 operator== 在命名空间中 性病 ,因此普通的查找将停止在那里,并且永远不会到达全局命名空间。

    在第二个示例中,重载是通过依赖于参数的查找找到的。除了非限定查找之外,此查找专门针对函数调用中的函数名执行,并在与调用的参数类型相关联的作用域中查找名称在本例中,namespace Foobar Foobar::Test ,因此依赖于参数的查找将搜索该命名空间并查找 Foobar::operator== .

    因此,逻辑上属于类公共接口一部分的自由函数(例如重载运算符)通常应该与类本身在同一个命名空间中定义,以使依赖于参数的查找能够工作。 std::operator==(矢量,矢量) 就是一个很好的例子- a==b 在您的示例中,通过依赖于参数的查找工作。

    推荐文章