I have a regular class (not a template, that is) with a private friend operator<<
it\'s declaration is:
std::ostream& operator<<(std:
My guess, from the description is that you are declaring two operator<<
but only defining one. For example:
namespace A {
struct B {
friend std::ostream& operator<<( std::ostream&, B const & ); // [1]
};
}
std::ostream& operator<<( std::ostream& o, A::B const & ) { // [2]
return o;
}
The line [1] declares one A::operator<<
function that can be found through ADL on the type B
, but [2] declares and defines ::operator<<
. When the compiler sees the code:
A::B b;
std::cout << b;
It use ADL and find A::operator<<
(from the friend declaration) and use it, but that function is undefined. If you remove the friend
declaration, there is a single instance of operator<<
declared and defined in the global namespace and that will be found by regular lookup.
Also note that this can be harder to spot if there are using directives in your program, as the definition in [2] might not explicitly name the A
namespace for the argument. This would also explain that you can define the rest of the members of the type:
// cpp [assume that the definition of B contained a member f
using namespace A;
void B::f() {
}
The definition of B::f
resides (in code) in the global namespace, but because of the using directive, B
will be found in the A
namespace and the type specifier will be equivalent to A::B
what makes the definition equivalent to void ::A::B::f() {}
after resolving B
. This will not happen for free functions.
I would recommend that you avoid using directives as they allow for subtle errors like this one. Also note that you can actually define the operator in the namespace explicitly (but you will need to also declare it in the namespace:
namespace A {
struct B { friend std::ostream& operator<<( std::ostream&, B const & ); };
std::ostream& operator<<( std::ostream&, B const & );
}
std::ostream& A::operator<<( std::ostream& o, B const & ) {
return o;
}
This trick (defining free functions outside of their natural namespace by fully qualifying) is sometimes use to avoid the definition of the function implicitly declaring it, which is prone to this type of errors. For example, if you defined the operator in the proper namespace, but the signature was slightly different:
namespace A {
struct B {
friend std::ostream& operator<<( std::ostream&, B const & ); // [1]
};
std::ostream& operator<<( std::ostream&, B & ) { // [3]
return o;
}
}
The definition in [3] is also a declaration, but it declares a function different than the one declared in [1], and you might end up scratching your head asking why the linker is not finding [1].
David gave a very good answer to the question. Here I am just providing an example for easy understanding.
in my header file:
namespace BamTools {
class SomeBamClass {
.....
public:
friend std::ostream& operator<<(std::ostream& ous, const SomeBamClass& ba);
.....
}
}
In the cpp file:
using namespace BamTools; // this work for Class member function but not friends
using namespace std;
........
std::ostream& operator<<(std::ostream &ous, const SomeBamClass &ba) {
// actual implementation
return ous;
}
The above will give you undefined reference to operator<<(.., const SomeBamClass&) when you try to link to this library from your own applications because it is declaration and implementation of an operator outside the namespace.
undefined reference to `BamTools::operator<<(std::ostream&, BamTools::SomeBamClass const&)'
The only thing works for me is to add namespace inclosure to the friend function in the implementation file:
namespace BamTools {
std::ostream& operator<<(std::ostream &ous, const SomeBamClass &ba) {
...
return ous;
}
}
using ... BamTools::operator<<(..., const BamTools::SomeBamClass&) will result in a compiler error for my g++ 5.4.0.