Search code examples
c++operator-overloadingstddisplayheap

Linker can't find overloaded operator<< while compiling. C++


I am working on implementing a templated heap class. It has been really rough so far. I am trying to display my heap but I am getting this error:

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

I used template in my class so the implementation of my functions in inside the header file as well, here is the hpp file: (!): No need to read the whole file, just the ostream& operator<<().

/*
 Header file for Heap implemenetation
 */

#ifndef Heap_hpp
#define Heap_hpp

#include <stdio.h>
#include <vector>
#include <iterator>
#include <string>
#include <iostream>



template<typename elementType>
class Heap{
private:
    std::vector<elementType> myVecrtor;
    int mySize = 1; //The minimum size is 1 since the first element is a dummy.
    void perculateDown(int root);
    void perculateUp();
    
public:
    Heap();
    bool checkEmpty();
    void insert(elementType iteam);
    int getSize();
    std::vector<elementType> getHeap();
    elementType getMax();
    int getMaxIndex();
    void removeMax();
    void removeAtIndex(int index);
    friend std::ostream& operator<<(std::ostream &out, Heap const &h);
    
};

template<typename elementType>
Heap<elementType>::Heap(){
}

template <typename elementType>
bool Heap<elementType>::checkEmpty(){
    if(mySize > 1)
        return true;
    else
        return false;
}

template <typename elementType>
void Heap<elementType>::insert(elementType iteam){
    auto it = mySize;//iterator
    //myVecrtor.insert(it, iteam);//insert after first element(dummy)
    mySize++;
    perculateUp();
}

template <typename elementType>
std::vector<elementType> Heap<elementType>::getHeap(){
    return  myVecrtor;
}

template <typename elementType>
elementType Heap<elementType>::getMax(){
    return myVecrtor[getMaxIndex()];
}

template <typename elementType>
int Heap<elementType>::getMaxIndex(){
    int maxIndex = 1;
    elementType max = myVecrtor[maxIndex];
    for(int i = 0; i < myVecrtor.size(); i++){
        if(max < myVecrtor[i])
            maxIndex = i;
    }
    return maxIndex;
}

template <typename elementType>
void Heap<elementType>::removeMax(){
    int maxIndex = getMaxIndex();
    myVecrtor[maxIndex] = myVecrtor[mySize];
    mySize--;
    perculateDown(maxIndex);
}

template <typename elementType>
void Heap<elementType>::removeAtIndex(int index){
    myVecrtor[index] = myVecrtor[mySize];
    mySize--;
    perculateDown(index);
}

template <typename elementType>
std::ostream& operator<<(std::ostream &out, const Heap<elementType> &h){//it is giving me the error here
    out<<"\t\tHeap:";
    for(int i = 0; i < h.mySize; i++){
        out<<h.myVecrtor.at(i);
    }
    return out;
}

template <typename elementType>
void Heap<elementType>::perculateUp(){
    int loc = mySize - 1;
    int parent = loc /2;
   // while(parent >= 1 && myVecrtor[loc] > myVecrtor[parent]){
        elementType temp = myVecrtor[parent];
        myVecrtor[parent] = myVecrtor[loc];
        myVecrtor[loc] = temp;
        loc = parent;
        parent = loc / 2;
   // }
}

template <typename elementType>
void Heap<elementType>::perculateDown(int root){
    int r = root, c = r*2;
    while (r < mySize - 1) {
        if(c < mySize && myVecrtor[c] < myVecrtor[c+1])
            c++;
        if(myVecrtor[r] < myVecrtor[c]){
            elementType temp = myVecrtor[r];
            myVecrtor[r] = myVecrtor[c];
            myVecrtor[c] = temp;
            r = c;
            c *= 2;
        }
        else
            break;
    }
}


#endif /* Heap_hpp */

I tried all my other functions to see if I had a silly mistake or something but all worked except this one: (!): ik the use of namespace std is a bad habbit but i am using just for testing

#include <vector>
#include "Heap.hpp"
#include <ostream>
using namespace std;

int main(int argc, const char * argv[]) {
    Heap<int> h;
    h.insert(5);
    h.getHeap();
    h.getMaxIndex();
    h.getMax();
    h.removeMax();
    h.removeAtIndex(1);
    h.getHeap();
    cout<<h;
    
}

I have no idea what's the problem, tho one thing I found very close to my problem is related to the namespace std, but didn't get anything out of it. Any help would be appreciated!


Solution

  • The friend declaration for operator<< that you currently have is for a non-template operator<<.

    There are 2 ways to solve this:

    Method 1

    To solve this replace that friend declaration with a declaration that has its own parameter clause so that you've a friend template declaration, inside the class with:

    template<typename elementType>
    class Heap{
        //other code as before
        public:
            template<typename U>
            friend std::ostream& operator<<(std::ostream &out, Heap<U> const &h);
        
    };
    

    Demo

    Method 2

    Here we can forward declare both the class template Heap and operator<<.

    //forward declaration for Heap<> 
    template<typename T> class Heap;
    
    //forward declaration for operator<<
    template<typename T> std::ostream& operator<<(std::ostream& os, Heap<T> const &h);
    
    template<typename elementType>
    class Heap{
      //other members as before
        
    public:
    
        friend std::ostream& operator<<<elementType>(std::ostream &out, Heap<elementType> const &h);
        
    };
    

    Demo