Sunday, September 15, 2013

Overloading << in C++

This error was pretty annoying in the linking stage as I was compiling my C++:

duplicate symbol __ZlsRNSt3__113basic_ostreamIcNS_11char_traitsIcEEEERK10Notation in:
    CMakeFiles/project1.dir/TwoTagExample.cc.o
    lib_notation_lib.a(Notation.cc.o)

I thought I was following all the rules and even thought maybe I was using a name already defined in some deep C++ library... I mean I was compiling with

clang++ -std=c++11 -stdlib=libc++ -g TwoTagExample.cc Helper.cc Notation.cc

(extra options for things like initializer_list and such).

Apparently I was overloading the << operator wrong. I thought I could put the implementation right in the .h file, but you have to implement it in the associated .cc/.cpp.

Bad Notation.h file:
class Notation {
  static const string GIVEN_DELIM;
  ...
};
ostream& operator<<(ostream& out, const Notation& n) {  // NO.
  return out << n.repr();
}

(The thing is this overloading works fine if you put the class and overloading function in a .cc/.cpp file, which was what I had in this hack of a project initially. But once I moved to a .h – nope.)

Good Notation.h file:
class Notation {
  static const string GIVEN_DELIM;
  ...
};
ostream& operator<<(ostream& out, const Notation& n);  // Yes.

(Good) Corresponding Notation.cc/.cpp file:
#include "Notation.h"

const string Notation::GIVEN_DELIM = "|";
...

ostream& operator<<(ostream& out, const Notation& n) { // Yes.
    return out << n.repr();
}

no one likes uninformative errors... but at least they make you play a good detective game.

Other reasons you might be getting the "duplicate symbol" error: more likely than this, you reused a method or variable name somewhere in the .h (shouldn't be defined twice) or across header files. Or you forgot your header guards (those #ifndef #define things that should be in header files but I left out for brevity here).

No comments:

Post a Comment

Please be considerate in what you say.