运算符<<重载隐藏其他 [英] Operator&lt;&lt; overloading hides other

查看:92
本文介绍了运算符<<重载隐藏其他的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个奇怪的操作符<<超载问题,我找不到原因.以下代码是问题的提取.此代码无法使用 VS2015、g++ 5.4.0 和 clang 3.8.0 进行编译,因此我认为这不是编译器错误.

I have a weird operator<< overloading problem, for which I can't find a reason. The following code is an extraction of the problem. This code fails to compile using VS2015, g++ 5.4.0 and clang 3.8.0, so I assume it's not a compiler bug.

#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;
}

编译器找不到operator<<的重载对于 std::exception(std::cout << ex << std::endl;"行失败).尤其让我困惑的是,如果我:

The compiler can't find the overloading of operator<< for std::exception (the line "std::cout << ex << std::endl;" fails). What especially confuses me is, if I either:

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

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

the code compiles. What is the reason for this behavior?

推荐答案

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

What you're seeing is a consequence of the name lookup rules in C++. This is why it is not recommended to provide operator overloads where there is not at least one operand of a class type that you wrote.

换句话说,你应该设计你的代码,使它没有 operator<<<(std::ostream&, std::exception) 因为它会无意中被其他 operator<< 不时在命名空间内.

In other words you should design your code so that it does not have operator<<(std::ostream&, std::exception) as it will inadvertantly be hidden by other operator<< inside namespaces from time to time.

这种行为对所有函数都是一样的,运算符名称不是特例.

This behaviour is the same for all functions, operator names are not a special case.

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

An alternative solution is to put using ::operator<<; inside any namespace in which you are defining more overloads of operator<<.

完整的名称查找规则集有点复杂.用于非限定函数名称查找的要点是:

The full set of name lookup rules is a bit complicated. The gist of it for unqualified function name lookup is:

  1. 参数相关查找搜索名称.
  2. 非 ADL 查找会搜索名称.
  3. 将 (1) 和 (2) 的结果组合起来生成查找集.

在你的代码中 o <<,第 1 步在类 std::ostream 中搜索成员 operator<<,并为非成员 std 搜索名称空间 std代码>运算符<<.

In your code o << s.m, step 1 searches class std::ostream for member operator<<, and namespace std for non-member operator<<.

第 2 步搜索:

  • ns::operator<< 的主体,以防您在该函数中有任何函数声明!(没有找到)
  • 命名空间 ns,直到并包括调用发生的函数点.(找到ns::operator<<)
  • The body of ns::operator<<, in case you had any function declarations inside that function! (nothing found)
  • namespace ns, up to and including the point of the function in which the call occurs. (Found ns::operator<<)

关键在于,一旦 ns::operator<<< 被非 ADL 查找找到,非 ADL 查找过程就会停止——它不会继续搜索进一步封闭的命名空间以找到更多重载.

The key point is that once ns::operator<< is found by non-ADL lookup, the non-ADL lookup process stops - it does not continue searching up further enclosing namespace to find more overloads.

最终的查找集是(1)和(2)的并集,即std::ostream::operator<<, std::operator<<code> 和 ns::operator<<<.然后重载解析只对那些限定名称的重载进行.

The final lookup set is the union of (1) and (2), i.e. std::ostream::operator<<, std::operator<<, and ns::operator<<. Then overload resolution proceeds only on overloads of those qualified names.

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

Here is a simpler example of the same principle, without the distraction of the ADL set being added in:

void bar(int);

namespace N
{
    void bar(char const *);

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

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

There is no ADL because the argument 1 is not of class type. Non-ADL unqualified lookup finds N::bar and stops. ::bar is not considered. The code fails to compile.

这篇关于运算符<<重载隐藏其他的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆