0

I'm currently learning how to overload the stream insertion operator for my class. Found below is the code I have:

#include <iostream>
#include <string>

using std::string;
using std::endl;
using std::cout;

template<typename T>
class A {
    public:
        A(T);
    friend std::ostream& operator<<(std::ostream&, const A&);
    T* value;
};

template<typename T>
A<T>::A(T input) {*value = input;}

template<typename T>
std::ostream& operator<<(std::ostream& out, const A<T>& obj) {
    out << *(obj.value);
    return out;
}

int main() {
    A<string> foo("HELLO");
    cout << foo << endl; 
    return 0;
}

I'm getting this error after compiling the code with G++

Undefined symbols for architecture x86_64:
  "operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, A<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&)", referenced from:
      _main in streamops-ef073c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Any idea what could be wrong? I'm following a guide and don't see the difference in my operator overload.

Chronollo
  • 322
  • 1
  • 9

2 Answers2

1

The problem is that the friend declaration declares the function as a non-template function.

You need to declare it as a template:

template<typename U>
friend std::ostream& operator<<(std::ostream&, const A<U>&);

Optionally you could define the function inline inside the class:

friend std::ostream& operator<<(std::ostream& out, const A& obj) {
    return out << *(obj.value);
} 
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
0

One option is to use a combination of a class member function and a non-member function.

template <typename T>
class A
{
    public:

        A(T);

        std::ostream& write(std::ostream& out) const
        {
           return out << *value;
        }

        T* value;
};


template <typename T>
std::ostream& operator<<(std::ostream& out, const A<T>& obj)
{
   erturn obj.write(out);
}


Word of caution for the way you have defined you class.

When the constructor gets invoked, your code will run into undefined behavior. You are using

*value = input;

without value having been initialized to point to a valid object. That is not good.

R Sahu
  • 204,454
  • 14
  • 159
  • 270