0

I've got a problem when printing out all the values of the class

#include <iostream>

const int LENGTH = 5;

template <typename T1, typename T2>
class Test {
private:
  T1 a;
  T2 b;

public:
  void setData(T1 a, T2 b)
  {
   this->a = a;
   this->b = b;
  }
  T1 get_a() { return a; }
  T2 get_b() { return b; }
  T2 sum() const;
  Test operator*(const Test& t0);
  friend std::ostream& operator<<(std::ostream& output, const Test<T1, T2>& t0);
};

template <typename T1, typename T2>
T2 Test<T1, T2>::sum() const
{
  return a + b;
}

template <typename T1, typename T2>
Test<T1, T2> Test<T1, T2>::operator*(const Test& t0)
{
 Test<T1, T2> t;
 t.a = this->a * t0.a;
 t.b = this->b * t0.b;
 return t;
}

template <typename T1, typename T2>
std::ostream& operator<<(std::ostream& output, const Test<T1, T2>& t0)
{
  output << t0.get_a() << ", " << t0.get_b() << std::endl;
  return output;
}

int main(int argc, char *argv[])
{
  Test<int, float> t1;
  t1.setData(3, 4.5);
  Test<int, float> t2;
  t2.setData(5, 6.7);
  Test<int, float> t3 = t1 * t2;
  std::cout << t1;
}

The last line it show me an error "undefined reference to operator<< ...". I think the error comes from the friend function of the class but i don't know how to fix it. Anyone can help me, please. I appreciate for your support, thank you!

Huy Vũ
  • 45
  • 7
  • Worth reading: David's *stellar* answer to this question: [overloading friend operator<< for template class](https://stackoverflow.com/a/4661372/1322972) – WhozCraig Aug 22 '18 at 15:48
  • You're describing the LAST error message emitted by your compiler, and ignoring errors that precede it. `get_a()` and `get_b()` member functions of (templated) `Test` are not `const`. Second argument of `operator<<()` is a `const` reference, so the calls `t0.get_a()` and `t0.get_b()` are invalid. This will result in error messages you are ignoring. This prevents instantiating the `operator<<()` - and the last error message you see. Voting to close as a typo (since leaving out a `const` is not much more than a typo). – Peter Aug 22 '18 at 15:53

3 Answers3

2

What your friend declaration says is that for any particular instantiation of Test with types T1 and T2, there is a non-template std::ostream& operator<<(std::ostream& output, const Test<T1, T2>& t0);. (g++ provides a helpful warning about this.)

But you defined a template function, which is not the same thing as what you declared.

You could define the operator inside the class, or make it a template, but you don't need a friend here at all since you're only using public members, so you can remove the whole friend declaration.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
1

this complies

#include <iostream>

const int LENGTH = 5;

template <typename T1, typename T2>
class Test;

template <typename T1, typename T2>
std::ostream& operator<<(std::ostream& output, const Test<T1, T2>& t0)
{
  output << t0.get_a() << ", " << t0.get_b() << std::endl;
  return output;
}

template <typename T1, typename T2>
class Test {
private:
  T1 a;
  T2 b;

public:
  void setData(T1 a, T2 b)
  {
   this->a = a;
   this->b = b;
  }
  T1 get_a() const { return a; }
  T2 get_b() const { return b; }
  T2 sum() const;
  Test operator*(const Test& t0);
  friend std::ostream& operator<< <T1, T2>(std::ostream& output, const Test<T1, T2>& t0);
};

template <typename T1, typename T2>
T2 Test<T1, T2>::sum() const
{
  return a + b;
}

template <typename T1, typename T2>
Test<T1, T2> Test<T1, T2>::operator*(const Test& t0)
{
 Test<T1, T2> t;
 t.a = this->a * t0.a;
 t.b = this->b * t0.b;
 return t;
}

int main(int argc, char *argv[])
{
  Test<int, float> t1;
  t1.setData(3, 4.5);
  Test<int, float> t2;
  t2.setData(5, 6.7);
  Test<int, float> t3 = t1 * t2;
  std::cout << t1;
}

the issue was that the class was expecting a non template function so the template function wasn't instantiated and consequantly not found at link-time.

modifications:

explicitly specified in the friend declaration that it is a specialization with the <T1, T2>

put the template declaration above otherwise it won't be find to be instantiated

forward declare above the operator<<'s definition.

add the missing const on the getters.

Tyker
  • 2,971
  • 9
  • 21
0

Here is an edit of the compiling code. I added const to get methods and removed the friend std::ostream& operator<<

#include <iostream>

const int LENGTH = 5;

template <typename T1, typename T2>
class Test {
private:
    T1 a;
    T2 b;

public:
    void setData(T1 a, T2 b)
    {
        this->a = a;
        this->b = b;
    }
    T1 get_a() const { return a; }
    T2 get_b() const { return b; }
    T2 sum() const;
    Test operator*(const Test& t0);
};

template <typename T1, typename T2>
T2 Test<T1, T2>::sum() const
{
    return a + b;
}

template <typename T1, typename T2>
Test<T1, T2> Test<T1, T2>::operator*(const Test& t0)
{
    Test<T1, T2> t;
    t.a = this->a * t0.a;
    t.b = this->b * t0.b;
    return t;
}

template <typename T1, typename T2>
std::ostream& operator<<(std::ostream& output, const Test<T1, T2>& t0)
{
    output << t0.get_a() << ", " << t0.get_b() << std::endl;
    return output;
}

int main(int argc, char *argv[])
{
    Test<int, float> t1;
    t1.setData(3, 4.5);
    Test<int, float> t2;
    t2.setData(5, 6.7);
    Test<int, float> t3 = t1 * t2;
    std::cout << t1;
}
PilouPili
  • 2,601
  • 2
  • 17
  • 31
  • 2
    why do you remove the friend function, sir? – Huy Vũ Aug 22 '18 at 15:38
  • @HuyVũ I trust he removed it because you declared it but defined entirely different function. – Öö Tiib Aug 22 '18 at 15:47
  • It does not serve any purpose in this case. operator<< needs to be static and you do not use any private methods of your class – PilouPili Aug 22 '18 at 15:48
  • @HuyVũ Make `operator <<` utilize the private `a` and `b` members of `Test` directly and the friending becomes *highly* relevant (and required). – WhozCraig Aug 22 '18 at 15:53
  • In that case you define your friend function in your class: friend std::ostream& operator<<(std::ostream& output, const Test& t0) { output << t0.get_a() << ", " << t0.get_b() << std::endl; return output; } – PilouPili Aug 22 '18 at 15:57