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< – 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
  • 60,978
  • 3
  • 37
  • 76
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,949
  • 8
  • 20
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,580
  • 2
  • 17
  • 30