Natjo
Natjo

Reputation: 2128

Linking error when overloading operator <<

I want to overload the << operator for my own struct saved in its own .hpp file like this:

#ifndef MY_STRUCTS_HPP
#define MY_STRUCTS_HPP

#include <iostream>
#include <string>

typedef struct {
    std::string a;
    std::string b;
} Info;

std::ostream &operator<<(std::ostream &o, const Info &rhs) {
    o << "Name: " << rhs.a << "\t" << rhs.b;
    return o;
}

#endif

This is how my main file looks like:

#include "InfoBuilder.hpp"
#include "myStructs.hpp"
#include <iostream>

// Overloading the operator exactly the same, but here works
// std::ostream &operator<<(std::ostream &o, const Info &rhs) {
//     o << "Name: " << rhs.a << "\t" << rhs.b;
//     return o;
// }

int main(){
    InfoBuilder s();

    std::cout << s.getArtistInfo("architects") << std::endl;

    return 0;
}

Compiling this gives this error:

CMakeFiles/foo.dir/src/InfoBuilder.cpp.o: In function `operator<<(std::ostream&, Info const&)':
InfoBuilder.cpp:(.text+0x159): multiple definition of `operator<<(std::ostream&, Info const&)'
CMakeFiles/foo.dir/src/main.cpp.o:main.cpp:(.text+0xa4): first defined here
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/foo.dir/build.make:126: foo] Error 1
make[1]: *** [CMakeFiles/Makefile2:68: CMakeFiles/foo.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

Commenting the overloaded operator out in the myStructs.hpp file and just defining it in the main.cpp file works. But why does this make a difference as I am using include guards? I also include myStructs.hpp in InfoBuilder.hpp.

Upvotes: 0

Views: 78

Answers (1)

Bill Lynch
Bill Lynch

Reputation: 81986

You've got two options:

Option 1: Put the implementation of your function in a cc file:

myStructs.hpp

#ifndef MY_STRUCTS_HPP
#define MY_STRUCTS_HPP

#include <iostream>
#include <string>

typedef struct {
    std::string a;
    std::string b;
} Info;

std::ostream &operator<<(std::ostream &o, const Info &rhs);

#endif

myStructs.cpp

#include <iostream>
#include <string>
#include "myStructs.hpp"

std::ostream &operator<<(std::ostream &o, const Info &rhs) {
    o << "Name: " << rhs.a << "\t" << rhs.b;
    return o;
}

Option 2: Mark the function as static

myStructs.hpp

#ifndef MY_STRUCTS_HPP
#define MY_STRUCTS_HPP

#include <iostream>
#include <string>

typedef struct {
    std::string a;
    std::string b;
} Info;

static std::ostream &operator<<(std::ostream &o, const Info &rhs) {
    o << "Name: " << rhs.a << "\t" << rhs.b;
    return o;
}

#endif

Upvotes: 1

Related Questions