4

Considering this snippet, as expected gcc cannot find which symbol to choose between NA::operator<< and NB::operator<< when calling stream operator without specifying namespace (by calling stream operator like 1)). It is possible to call NB::operator<< explicitely (like 2). This runs and have the expected behaviour. But a build error is raised when trying to do the same with friend stream operator (like 3), telling that operator<< is not a member of NA. Why? NA::operator<< seems to be found in case 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);
}

My question is, how to explicitely call NA::operator<< ?

FlashMcQueen
  • 635
  • 3
  • 13

1 Answers1

1

This cas is a little bit weird.

For this code :

ofs << *a;

The compiler clearly states that there is ambiguity between the two :

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) {
                                      ^~~~~~~~

But when calling explicitly the operator by

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

The compiler doesn't find it :

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

The only workaround I found is to declare a function in the namespace NA which will call the operator, then the compiler is able to select the good one :

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

Okay, I got it thanks to the comment of @Passer By

Declaring the function friend won't be lookable by the compiler, adding a forward declaration of the method like :

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

permits the compiler to find the declaration, hence

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

wiil be resolved by the compiler.

dkg
  • 1,775
  • 14
  • 34