-2

Important Update: Removing the delegation of friend solved the problem Partially but why? and how may I keep it as friend...

Why the following code gets me linker error?

Dimensions dims2(3 ,14);//Fixed class 100% the bug isn't cause by it
Matrix<int> mat_2(dims2, 5);
std::cout << mat_2;

My class:

template<class T>
class Matrix {
public:
    friend std::ostream &operator<<(std::ostream &os, const Matrix<T> &matrix);

;}

in .h file I have:

template<typename T>
std::ostream &operator<<(std::ostream &os, const Matrix<T> &matrix) {}

I get the following:

Undefined symbols for architecture x86_64:
"mtm::operator<<(std::__1::basic_ostream >&, mtm::Matrix const&)", referenced from: _main in main.cpp.o ld: symbol(s) not found for architecture x86_64

clang: error: linker command failed with exit code 1 (use -v to see invocation)

  • 2
    Please [stop creating new accounts and posting duplicate questions](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file). If you're going to go through the trouble of doing all that, at least read the [help], take the [tour], and learn the requirements for a [mre], without which it is unlikely that anyone will be able to tell you anything. – Sam Varshavchik Jun 14 '20 at 00:58
  • 1
    I created a new one because you closed my question and couldn't publish new one, plus my code is minimal. do you see anything missing –  Jun 14 '20 at 01:01
  • 1
    Yes, you are missing a [mre]. Unless anyone can cut/paste what's in the question, ***exactly as shown*** and can reproduce your error themselves, it is unlikely that anyone will be able to tell you anything. – Sam Varshavchik Jun 14 '20 at 01:01
  • If I can reproduce the issue with few lines then why would I need to ask for help... –  Jun 14 '20 at 01:02
  • I don't know what's the root cause for this,**I have to add that deleting the call to that function no longer causes a linker error** –  Jun 14 '20 at 01:03
  • Well, if you don't understand the reason, that would be one. But it's not you who needs to "reproduce the issue with few lines", but everyone else, based only on what's shown in the question. As shown, nobody else can, for one reason the mysterious `Matrix` template class is not defined anywhere. – Sam Varshavchik Jun 14 '20 at 01:03
  • I have exposed the class –  Jun 14 '20 at 01:06
  • 1
    quite often you will find that when you try to create a small isolated case you will actually discover the error yourself. – pm100 Jun 14 '20 at 01:07
  • Which is still not a [mre], because now the `Dimension` class is not defined anywhere. Please try to cut/paste everything you have shown in your question, save it to a file ***exactly as shown***, attempt to compile it, and unless you get the exact compilation or a linker error you're asking about, then by definition, it's not a [mre]. How do you expect anyone to help you figure out the reason for the compilation error, unless they cannot reproduce it themselves? – Sam Varshavchik Jun 14 '20 at 01:08
  • @SamVarshavchik I wanted to help and save you time I can say that there is no single bug from that class –  Jun 14 '20 at 01:08
  • 1
    Ok, then if you're certain of that, then I don't see any issue based solely on the shown code; and I doubt, very much, that anyone else will too. If you ever manage to put together something that meets all the requirements for a [mre], then this can be reviewed. That's it. – Sam Varshavchik Jun 14 '20 at 01:10
  • @SamVarshavchik I have exposed the second class too, please read the important update at the top –  Jun 14 '20 at 01:11
  • How and where does namespace `mtm` get into the picture? It doesn't appear in the code shown, but does appear in the error message. My guess is, you declare `operator<<` inside that namespace, but define it outside. – Igor Tandetnik Jun 14 '20 at 01:12
  • 1
    Please try to compile the shown code, ***exactly as is***, yourself. It will not compile, spewing forth a bunch of errors that have nothing to do with what's asked here. It's painfully clear that you haven't even bothered to do that. If you'd like to ask other people to spend some of their time helping you, it's only fair to ask you spend a little bit of time preparing, constructing, and putting together a helpful question containing a single, self-contained code snippet that anyone can cut/paste, compile, and reproduce the error. The shown code is nowhere close to being in that state. – Sam Varshavchik Jun 14 '20 at 01:14
  • @IgorTandetnik two my my classes are inside mtm and the implementations too –  Jun 14 '20 at 01:17
  • @SamVarshavchik do you really want me to publish the implementation of every single function here? –  Jun 14 '20 at 01:17
  • 1
    The compiler appears to believe otherwise. That's why it's important to show a [mcve]. You keep insisting that everything's fine with the code not shown - but if everything were fine, you wouldn't be here asking this question. – Igor Tandetnik Jun 14 '20 at 01:18
  • 1
    Not, not every function. Just what's needed for a [mre]. – Sam Varshavchik Jun 14 '20 at 01:18
  • I just don't know what is missing for 'minimal reproducible example' just ask for which function you want –  Jun 14 '20 at 01:22
  • 1
    I repeat: "something that ***anyone in the world*** can cut/paste, ***exactly as shown***, and be able to reproduce your error"; and which part of that is not clear to you? Can you take what you see in your question ***and only that***, then cut/paste into a separate file, then attempt to compile, and get the same compilation error you're asking about, and only that. Unless you can answer "yes", this is not a [mre]. – Sam Varshavchik Jun 14 '20 at 01:25

1 Answers1

0
friend std::ostream &operator<<(std::ostream &os, const Matrix<T> &matrix);

This declares a non-template function named operator<< (in the namespace enclosing Matrix definition). That function is never defined. In addition, a function template also named operator<< is defined. When doing overload resolution, the compiler prefers a non-template over the template, then the linker discovers there's no definition.

There are several ways to resolve this. One is to define the operator in-class:

template<class T>
class Matrix {
    friend std::ostream& operator<<(std::ostream& os, const Matrix<T>& matrix) {
      // Implementation here
    }
};

Another is to befriend the function template:

template <typename T> class Matrix;

template<typename T>
std::ostream &operator<<(std::ostream &os, const Matrix<T> &matrix);

template<class T>
class Matrix {
    friend std::ostream& operator<< <T>(std::ostream &os, const Matrix<T> &matrix);
};

Yet third is to not require friendship at all, e.g. like this:

template<class T>
class Matrix {
public:
    // Actual implementation here.
    void PrintMe(std::ostream &os);
};

template<typename T>
std::ostream &operator<<(std::ostream &os, const Matrix<T> &matrix) {
  matrix.PrintMe(os);
  return os;
}
Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85