c – 运算符超载cl和g不同的输出

前端之家收集整理的这篇文章主要介绍了c – 运算符超载cl和g不同的输出前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
使用这个示例程序,我观察到g和clang中的不同行为

foo.h中:

#include <iostream>

namespace Bar
{

class Foo
{
public:

    Foo(int x) : _x(x)
    {}

    int x() const
    {
        return _x;
    }

private:

    int _x;
};

}

std::ostream& operator <<(std::ostream& os,const Bar::Foo* foo);

Foo.cpp中

#include <Foo.h>

using namespace std;

ostream& operator <<(ostream& os,const Bar::Foo* foo)
{
    return os << foo->x();
}

main.cpp中

#include <iostream>

using namespace std;

template<typename T>
void print(const T& t)
{
    cout << t << endl;
}

#include <Foo.h>

int main(int argc,char** argv)
{
    Bar::Foo* foo = new Bar::Foo(5);
    print(foo);
}

用俚语和g编译产生不同的结果:

air:~ jose$clang++ Foo.cpp main.cpp -I.
air:~ jose$./a.out
0x7ff9e84000e0
air:~ jose$g++ Foo.cpp main.cpp -I.
air:~ jose$./a.out
5

哪一个是正确的,为什么?

解决方法

在这种特殊情况下,cl声是正确的.

问题是如何在模板打印中执行查找.在表达式中,打印对运算符<<是依赖的依赖名称名称解析在14.6.4中处理:

In resolving dependent names,names from the following sources are considered:

— Declarations that are visible at the point of definition of the template.

— Declarations from namespaces associated with the types of the function arguments both from the instantiation context (14.6.4.1) and from the definition context.

在您的情况下,您的运算符的声明在模板定义点不可见,因为标题之后包含,并且它不存在于函数参数的任何关联命名空间中(即:: std for: :std :: ostream and :: Bar for :: Bar :: Foo *),所以它不会被找到.

现在,:: std中有一个重载,它占用一个void *,这将由Argument Dependent Lookup找到. :: Bar :: Foo *将被转换为一个void *,并打印地址.

也就是说,在标准兼容的编译器中.

我忘了在这里添加,只留在评论中,但它是足够重要的:

始终在同一个名称空间中定义适用于您的类型的运算符,该名称空间中包含它们应用的类型.让论据依赖查找对你来说是个魔术.它是专门为了这个特殊目的而设计的,使用它.

猜你在找的C&C++相关文章