0

(this is an old exam for my current course)

I'm trying to overload operator<< in a template class but when I compile the code and run the program i get this message:

/usr/bin/ld: /tmp/cc2BvB2u.o: in function `main':
/home/user/Skola/TDDI82/TENTA2017_1/UPPGIFT4/main.cpp:30: undefined reference to `operator<<(std::ostream&, Wrapper<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&)'
/usr/bin/ld: /home/user/Skola/TDDI82/TENTA2017_1/UPPGIFT4/main.cpp:31: undefined reference to `operator<<(std::ostream&, Wrapper<int> const&)'
/usr/bin/ld: /home/user/Skola/TDDI82/TENTA2017_1/UPPGIFT4/main.cpp:32: undefined reference to `operator<<(std::ostream&, Wrapper<int> const&)'
collect2: error: ld returned 1 exit status

All the other tests (my cout:s) are acting as I would expect. Down below here I've put all my code for this program. When I have used friend for overload of operator<< this hasn't been a problem. Anyone knows what wrong I'm doing and how to solve it?

//wrapper.h

#ifndef WRAPPER_H
#define WRAPPER_H

#include <ostream>

template<typename T>
class Wrapper
{
public:

    Wrapper();
    Wrapper(T const&);
    Wrapper(Wrapper const&);

    T get_value() const;
    void set_value(T const& v);

    Wrapper& operator=(T const& rhs);
    
    friend std::ostream& operator<<(std::ostream& os, typename Wrapper<T>::Wrapper const& w);
private:
    T value;
};

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


#include "wrapper.tcc"

#endif

//wrapper.tcc

#ifndef WRAPPER_TCC
#define WRAPPER_TCC

#include "wrapper.h"

template<typename T>
Wrapper<T>::Wrapper()
    :  value{}
    {}

template<typename T>
Wrapper<T>::Wrapper(T const& t)
    :   value{t}
    {}

template<typename T>
Wrapper<T>::Wrapper(Wrapper const& w)
{
    *this = w;
}

template<typename T>
T Wrapper<T>::get_value() const
{
    return value;
}

template<typename T>
void Wrapper<T>::set_value(T const& v) 
{
    value = v;
}

template<typename T>
typename Wrapper<T>::Wrapper& Wrapper<T>::operator=(T const& rhs)
{
    value = rhs;
    return *this;
}

template<typename T>
std::ostream& operator<<(std::ostream& os, typename Wrapper<T>::Wrapper const& w)
{
    os << w.get_value();
    return os;
}

#endif

//main.cpp

#include "wrapper.h"
#include <stream>
#include <string>

int main()
{
    //test
    Wrapper<std::string> w1{"hej"};
    Wrapper<int> w2{3};
    Wrapper<int> w3{w2};
    std::cout << w1.get_value() << std::endl;
    std::cout << w2.get_value() << std::endl;
    std::cout << w3.get_value() << std::endl;

    w1.set_value("nej");
    w2.set_value(10);
    w3.set_value(20);
    std::cout << w1.get_value() << std::endl;
    std::cout << w2.get_value() << std::endl;
    std::cout << w3.get_value() << std::endl;

    w3 = w2;
    w1 = "men...";
    std::cout << w1.get_value() << std::endl;
    std::cout << w2.get_value() << std::endl;
    std::cout << w3.get_value() << std::endl;

    w1 = "jo..";
    w2 = 42;
    std::cout << w1;
    std::cout << w2;
    std::cout << w3;
    //




    return 0;
}

Thanks if you spent your time on this problem!

exer240
  • 27
  • 4

1 Answers1

2

There are few problems with your code.

  • Missing Constructor
template<typename T>
Wrapper<T>::Wrapper(T const& w): value(w){ }
  • Wrapper<T>::Wrapper is a constructor is just nothing meaningful. Wrapper<T>::Wrapper doesn't raise any error because of SFINAE
std::ostream& operator<<(std::ostream& os, Wrapper<T> const& w){ ... }
  • Return Wrapper<T>& instead of Wrapper<T>::Wrapper
Wrapper<T>& Wrapper<T>::operator=(T const& rhs) { ... }
  • std::cout is defined in iostream

Link to the demo

Checkout this answer on When is typename required

Ch3steR
  • 20,090
  • 4
  • 28
  • 58
  • afaik constructors don't have names and `Wrapper::Wrapper` is just ... nothing meaningful – 463035818_is_not_an_ai May 28 '21 at 14:39
  • I have implemented the constructor where I have T as parameter. Thanks for the other corrections, but still I get the "undifined referece..." error. – exer240 May 28 '21 at 14:40
  • @463035818_is_not_a_number Makes senses, SFINAE kicks in here I guess if I'm not wrong. – Ch3steR May 28 '21 at 14:41
  • @exer240 Have you checked this link https://godbolt.org/z/xnaTcd567 – Ch3steR May 28 '21 at 14:43
  • Thanks, I missed the "template friend std::ostream& operator<<(std::ostream& os, Wrapper const& w);" part. Now it works, thanks again! However I do not understand why it works. Do you have any good link where I can read about it? – exer240 May 28 '21 at 14:46
  • @exer240 This [answer](https://stackoverflow.com/q/7923369/12416453) helped me understand when to use `typename`, I'm not an expert, started learning C++ a few months back. I started with the book suggestions given [here](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) – Ch3steR May 28 '21 at 14:50