Issue
I'm trying to overload the <<
operator for one of my classes, but the linker keeps failing to find the overload. Been searching online for anything I've missed on how to declare and implement the operator overload but nothing seems to stand out to me. Any ideas how I can fix this?
Undefined symbols for architecture x86_64:
"memath::operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, memath::Vector3 const&)", referenced from:
_main in mecli.cxx.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
vector3.h
#include <string>
#include <iostream>
namespace memath {
class Vector3 {
public:
double x;
double y;
double z;
Vector3();
std::string to_string() const;
friend std::ostream& operator<<(std::ostream &strm, const Vector3 &a);
};
};
vector3.cxx
#include <string>
#include <iostream>
#include <sstream>
#include "vector3.h"
using namespace memath;
Vector3::Vector3() : Vector3(0, 0, 0) {}
std::string Vector3::to_string() const {
std::ostringstream r;
r << "Vector3" << "(" << this->x << "," << this->y << "," << this->z << ")";
return r.str();
}
std::ostream& operator<<(std::ostream &strm, const Vector3 &a) {
strm << a.to_string();
return strm;
}
mecli.cxx
#include <iostream>
#include <cstdlib>
#include <string>
#include "vector3.h"
int main(int argc, char** argv) {
memath::Vector3 vec1;
std::cout << vec1 << std::endl;
}
Solution
because Vector3
is in namespace memath
the friend declaration declares memath::operator<<
, but you then define ::operator<<
. So just make the definition match the declaration:
std::ostream& memath::operator<<(std::ostream &strm, const Vector3 &a) {
// ^~~~~~~~
Follow up question, why doesn't the
using namespace memath;
seem to matter at the top of the file in this case and exclude this operator overload in particular?
It isn't particular to this operator. Actually is not particular to operators. You get the same behavior with function. And it's not particular to friend declarations.
So let's see this on a simpler example:
namespace ns
{
struct X
{
int foo(int); // => ::ns::X::foo
};
int bar(int); // => ::ns::bar
}
using namespace ns;
int X::foo(int a) { return a + 1; } // (1) => ::ns::X::foo
int bar(int a) { return a * 2; } // (2) => ::bar
Just like in your example, foo
works as you expect, but bar
is ambiguous, just like your operator<<
. So what's the difference between the two? Here's a simplified explanation:
(1): this is the definition of the qualified name foo
. X::
is what makes it qualified. So foo
is searched within X
. But what is X
? X
is an unqualified name-id. So now an unqualified lookup is performed for X
. This means X
is searched in the current namespace (global) and in all namespaces brought in by the using
directives. In this case X
is found only in namespace ns
. So X::foo
is resolved to ns::X::foo
which makes it the declaration of the method foo
of the class ns::X
.
(2) this is the definition of the unqualified name bar
. Since bar
is unqualified this is interpreted as the declaration of the name bar
in the current namespace (the global namespace). Because bar
is a new name being declared a lookup is not performed. So bar
is the declaration of ::bar
.
Please keep in mind this is a simplified explanation.
Answered By - bolov