如何明确呼叫好友流运营商?

时间:2018-07-31 12:11:38

标签: c++ gcc

考虑到此片段,按预期,gcc在调用流运算符而未指定名称空间时(通过调用像1那样的流运算符)找不到NA :: operator <<和NB :: operator <<之间的哪个符号。可以显式调用NB :: operator <<(如2)。运行并具有预期的行为。但是,当尝试与好友流运算符(如3)进行相同操作时,会产生一个构建错误,告诉运算符<<不是NA的成员。为什么? NA :: operator <<似乎在情况1)...

#include <iostream>
#include <vector>

#include <fstream>

namespace NA {
    class A {
        friend inline std::ostream & operator<<(std::ostream & s, const A & object) {
            std::cout << "NA::operator<<" << std::endl;
            return s;
        }
    };
}

namespace NB {
    std::ostream & operator<<(std::ostream & s, const NA::A & object) {
        std::cout << "NB::operator<<" << std::endl;
        return s;
    }
    void func(const NA::A* a);
}

void NB::func(const NA::A* a) {
    std::ofstream ofs;
    //1)
    //ofs << *a; //build error:
    //error: ambiguous overload for 'operator<<' (operand types are 'std::ofstream' {aka 'std::basic_ofstream<char>'} and 'const NA::A')
    //2)
    //NB::operator<<(ofs, *a); //runs and displays NB::operator<<
    //3)
    NA::operator<<(ofs, *a); //build error:
    //error: 'operator<<' is not a member of 'NA'
}

int main()
{
    NA::A obj_a;
    NB::func(&obj_a);
}

我的问题是,如何显式调用NA :: operator <<?

1 个答案:

答案 0 :(得分:1)

这个cas有点奇怪。

对于此代码:

ofs << *a;

编译器清楚地指出两者之间存在歧义:

main.cpp:16:20: note: candidate: 'std::ostream& NB::operator<<(std::ostream&, const NA::A&)'
     std::ostream & operator<<(std::ostream & s, const NA::A & object) {
                    ^~~~~~~~

main.cpp:8:38: note: candidate: 'std::ostream& NA::operator<<(std::ostream&, const NA::A&)'
         friend inline std::ostream & operator<<(std::ostream & s, const A & object) {
                                      ^~~~~~~~

但是当通过

显式调用运算符时
NA::operator<<(ofs, *a);

编译器找不到它:

main.cpp:39:17: error: 'operator<<' is not a member of 'NA'
    NA::operator<<(ofs, *a);
                ^~

我发现的唯一解决方法是在名称空间NA中声明一个函数,该函数将调用运算符,然后编译器可以选择一个好的函数:

namespace NA {
    void print_it(std::ofstream & os, const A & a)
    {
        os << a;
    }
}

好的,我感谢@Passer By的评论

在编译器中看不到函数的声明,而是添加如下方法的前向声明:

namespace NA {
    class A;
    std::ostream & operator<<(std::ostream & s, const A & object);
}

允许编译器查找声明,因此

NA::operator<<(ofs, *a);

将由编译器解决。