【问题标题】:Operator<< overloading hides other运算符<<重载隐藏其他
【发布时间】:2017-02-27 08:39:36
【问题描述】:

我有一个奇怪的运算符

#include <iostream>
#include <stdexcept>

inline std::ostream &operator<<(std::ostream &o, const std::exception &ex) {
    o << ex.what();
    return o;
}

namespace ns {
    struct Struct { int m; };

    inline std::ostream &operator<<(std::ostream &o, const Struct &s) {
        o << s.m;
        return o;
    }

    void fn() {
        std::cout << Struct{ 1 } << std::endl;
        try {
            throw std::runtime_error("...");
        } catch (std::exception &ex) {
            std::cout << ex << std::endl;
        }
    }
}

int main() {
    return 0;
}

编译器找不到 std::exception 的 operator

  • 删除重载运算符
  • 如果我将所有代码从命名空间 ns 移动到全局命名空间

代码编译。这种行为的原因是什么?

【问题讨论】:

  • 是什么阻止了您发布编译器消息/错误?
  • @Nawaz:我不知道是什么阻止了 OP,但一个原因可能是错误消息,当我现在在 GCC 中尝试时,错误消息是 202 行和 16799 个字符。 Bjarne 无法让他重载的隐式空格获得批准,但 C++ 确实设法用它的错误消息来欺骗我们......
  • 对不起:VS2015 说:严重性代码描述项目文件行抑制状态错误 C2679 二进制“.
  • @hob-B1T:在问题本身中发布错误消息。它是问题本身的部分

标签: c++ operator-keyword


【解决方案1】:

您看到的是 C++ 中名称查找规则的结果。这就是为什么不建议在您编写的类类型中没有至少一个操作数的情况下提供运算符重载的原因。

换句话说,您应该设计您的代码,使其不包含operator&lt;&lt;(std::ostream&amp;, std::exception),因为它会不时被命名空间内的其他operator&lt;&lt; 隐藏。

此行为对于所有函数都是相同的,运算符名称不是特殊情况。

另一种解决方案是将using ::operator&lt;&lt;; 放在您定义更多operator&lt;&lt; 重载的任何命名空间中。


全套名称查找规则有点复杂。非限定函数名查找的要点是:

  1. argument-dependent lookup 搜索姓名。
  2. 非 ADL 查找搜索名称。
  3. 将 (1) 和 (2) 的结果组合起来生成查找集。

在您的代码 o &lt;&lt; s.m 中,第 1 步在类 std::ostream 中搜索成员 operator&lt;&lt;,并在命名空间 std 中搜索非成员 operator&lt;&lt;

第 2 步搜索:

  • ns::operator&lt;&lt; 的主体,以防你在该函数中有任何函数声明! (未找到)
  • 命名空间ns,直到并包括调用发生的函数点。 (发现ns::operator&lt;&lt;

关键是,一旦非 ADL 查找找到 ns::operator&lt;&lt;,非 ADL 查找过程就会停止 - 它不会继续搜索进一步封闭的命名空间以查找更多重载。

最终的查找集是 (1) 和 (2) 的并集,即 std::ostream::operator&lt;&lt;std::operator&lt;&lt;ns::operator&lt;&lt;。然后重载决议只在那些限定名称的重载上进行。


这是一个相同原理的更简单示例,没有添加 ADL 集的干扰:

void bar(int);

namespace N
{
    void bar(char const *);

    void nfunc() { bar(1); }
}

没有 ADL,因为参数 1 不是类类型。非 ADL 不合格查找找到 N::bar 并停止。不考虑::bar。代码编译失败。

【讨论】:

  • Koenig lookup 值得一提作为进一步的参考吗?
  • @AdrianColomitchi 在我的回答中添加了一个 cppreference 链接
猜你喜欢
  • 1970-01-01
  • 2020-10-13
  • 2011-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-25
  • 2021-12-23
相关资源
最近更新 更多