c++ - Clang 和 g++ 对运算符重载的处理方式不同?

标签 c++ namespaces operator-overloading rvalue

我正在使用 C++14(-std=c++1y 在 g++ 4.9.1 和 clang 3.5 上)。

首先,这是附件 A(存在 Foo 命名空间的地方):

#include <iostream>
#include <sstream>

namespace Foo
{
    struct A
    {};
}

void operator<<(std::ostream &os, Foo::A const &a)
{}

int main()
{
    Foo::A a;

    std::ostringstream() << a;

    return 0;
}

Clang 和 g++ 都对此感到厌恶,尽管出于不同的原因。


图表 B(没有 Foo 命名空间):

#include <iostream>
#include <sstream>

struct A
{};

void operator<<(std::ostream &os, A const &a)
{}

int main()
{
    A a;

    std::ostringstream() << a;

    return 0;
}

g++ 仍然 barfs,但 Clang 成功编译。

这样的期望合理吗?这是怎么回事?

最佳答案

首先,标准提供了一个包罗万象的东西 operator<<对于右值输出流 ([ostream.rvalue])

template <class charT, class traits, class T>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>&& os, const T& x);

Effects: os << x

Returns: os

(右值输入流也有匹配的 operator>> - 参见 [istream.rvalue]。)

这是 operator<<被调用。

其次,与模板一样,在这个函数模板的主体中,对 operator<< 的非限定查找在 os << x是在模板定义上下文中完成的,它没有你的 operator<<可用的。相反,您的重载必须由 ADL 找到,这反过来意味着它必须位于与 A 相同的命名空间中。 .

您的第二个版本应该可以编译,并且在这两种情况下,编译器确实发现您的重载很好。问题是 libstdc++ 的实现(归结为 return os << x; )是不符合标准的,因为它假定 os << x必须返回 os .没有这样的要求。

编辑:libstdc++ 错误报告是 here ;它已在 trunk 中得到修复,并且已将修复程序反向移植到 4.8 和 4.9 分支。

关于c++ - Clang 和 g++ 对运算符重载的处理方式不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29234258/

相关文章:

c++ - 子类包含基类使用的静态成员

python - 函数命名空间概念(赋值前引用)

python - 删除 b/__init__.py 并使用不同的代码创建 b.py 后,输出不会改变?

c++ - 为什么在赋值运算符重载中返回引用?

c++重载下标运算符的两个版本

c++ - 在 Mac OS 上使用 GCC 为 MS-DOS (DOSBox) 编译 C 程序

c++ - 'cl' 未被识别为内部或外部命令,

c++ - 你可以在类声明中拥有而在 union 声明中永远不会遇到的一件事是什么?

go - 列出 Go 中 k8s 中的所有命名空间

python - 关于 __getattr__ 和 __getattribute__ 的一些问题?