简体   繁体   English

运算符<<重载决议(C++)

[英]operator<< overload resolution (C++)

The code below gives an error in the a::b::print function: Invalid operands to binary expression ('std::ostream' (aka 'basic_ostream<char>') and 'Foo') .下面的代码在a::b::print function: Invalid operands to binary expression ('std::ostream' (aka 'basic_ostream<char>') and 'Foo')中给出错误。

The error goes away if I comment out the operator<< overload in namespace b .如果我注释掉命名空间b中的operator<<重载,错误就会消失。 But I don't understand why that makes a difference because it has a different signature to the operator<< overload in namspace a .但我不明白为什么这会有所不同,因为它与 namspace a中的operator<<重载具有不同的签名。 What's going on?!这是怎么回事?!

#include <iostream>

class Foo {};

namespace a {

  std::ostream &operator<<(std::ostream &os, Foo &foo);
  void print(Foo& foo) {
    std::cout << foo;
  }

  namespace b {
    std::ostream &operator<<(std::ostream &os, double d); // uncomment to resolve error
    void print(Foo& foo) {
      std::cout << foo; // error here
    }
  }
}

As namespace b is nested inside namespace a , names declared in b will hide names declared in a .由于命名空间b嵌套在命名空间a中,因此在b中声明的名称将隐藏在a中声明的名称。 When name lookup occurs in a::b::print , it searches b , and if it doesn't find what it's looking for continues searching in a .当在a::b::print中进行名称查找时,它会搜索b如果没有找到它要查找的内容,则继续在a中搜索。 So it does find operator<< in b and stops looking, and does not even consider the proper one in a .所以它确实在b中找到 operator<< 并停止查找,甚至不考虑在a中正确的那个。 When you comment it out, it doesn't find it in b , and continues searching into a and finds it.当您将其注释掉时,它在b中找不到它,并继续搜索a并找到它。 You could fix this by adding this in namespace b:您可以通过在命名空间 b 中添加它来解决此问题:

using a::operator<<; 

However, the real problem with your code is that you're not utilizing ADL (argument dependent lookup) properly.但是,您的代码的真正问题是您没有正确使用 ADL(参数相关查找)。 Operators that work on user defined types should be in the same namespace as the types they operate on.对用户定义类型起作用的操作符应该与它们操作的类型在同一个命名空间中。 What ADL does is add extra namespaces to search, so that any arguments (or template parameters) involved with the call will have their namespace considered--automatically. ADL 所做的是添加额外的命名空间以进行搜索,以便与调用相关的任何 arguments(或模板参数)都会自动考虑其命名空间。 (This is why you can use the operators provided in the std namespace for builtin types when your code is outside std .) (这就是为什么当您的代码在std之外时,您可以将std命名空间中提供的运算符用于内置类型。)

So move operator<< out of namespace a and into the same (global) namespace where Foo is.因此,将operator<<移出命名空间a并进入Foo所在的相同(全局)命名空间。 Or, probably better, move Foo into namespace a .或者,可能更好,将Foo移动到命名空间a中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM