Question

I'm relatively new to C++, and currently working on an assignment using vectors and ostream to print out a vector which contains other vectors inside. However I am currently getting this error when I try to run the program: symbol not found

operator<<(std::basic_ostream<char, std::char_traits<char> >&, Hash_Table<Entry, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&)", referenced from: _main in main.o

here is my main() code

int main(){

Hash_Table<Entry,string> newTable(11);


// insert
Entry newEntry;
newEntry.setKey("cat");
newTable.insert(newEntry);

//print Dictionary
cout << "Dictionary contains:";
cout << newTable;

cout << '\n';

    return 0;
}

here is my Entry class:

class Entry {
public:
Entry();
string getKey();
void setKey(string key);
int getHash(int M);
friend istream& operator>> (istream& in, Entry& right);
friend ostream& operator<< (ostream& out, const Entry& right);

private:

string data;
};

Here is my Hash_Table class:

template <typename T,typename K>
class Hash_Table {
public:
Hash_Table(int size); 
void insert(T newEntry); 
T* search(K key); 
void delete_entry(T* entry);
friend ostream& operator<< (ostream& out, const Hash_Table& right);
private:
vector< vector<T> > hashTable;
};

And lastly here is my function to print the vector....

template <typename T,typename K>
ostream& operator<< (ostream& out, const Hash_Table<T,K>& right) {
for (int i=0; i < right.hashTable.size(); i++)
    for (int j=0; j < right.hashTable[i].size(); j++) 
        out << "Slot " << i << ", Entry " << j
        << "\n" << right.hashTable[i][j] << "\n\n";
return out;
}

Basically I am attempting to implement a Dictionary (ADT). The hash table is a vector of vectors... so far everything seems to work... however I cant get it to print the contents of the vector out to the console. I should be about to print out a vector with cout << newTable;.... but I keep getting this error. From what I understand, my printing function should work... am I overlooking something??

Was it helpful?

Solution 2

This is part of the annoyance of templates and friend functions. When you declare that you're writing a friend function within a template class, the compiler does not actually recognise that the friend function itself is a template. One way of fixing this is to use member templates:

template <typename T, typename K>
class Hash_Table
{
    //....

    template <typename T2, typename K2>
    friend ostream& operator<< (ostream& out, const Hash_Table<T2, K2>& right);
};

Then in the definition:

template <typename T, typename K>
ostream& operator<<(ostream& out, const Hash_Table<T, K>& f)
{
    //Code as before
}   

For more information, see here, although be warned, it may make your head hurt a bit.

OTHER TIPS

However I am currently getting this error when I try to run the program: symbol not found

I guess by "running" you mean compiling, because this is a compiler error, not a runtime error.

The problem is propbably that you defined your operator<< in a .cpp file, so that it is not visible to the compiler. With normal classes and functions, that's ok, but with templates it is not, as the compiler needs to see the template definition whe you intantiate the template.

The solution would be to put the operator definition in the header that defines the Hash_Table class template. You will probably run into similar errors regarding the member functions of Hash_Table.

Another problem is, as noted by Yuushi, the templated operator declared a friend of the class. It's a matter of taste, but I usually refrain completely from declaring friend functions if there is another solution, and there is:

template <typename T, typename K>
class Hash_Table {
    //....

  void printToStream(std::ostream& os) const {
    //your output algorithm here
  }
};

template <class T, class K>
std::ostream& operator<<(std::ostream& os Hash_Table<T,K> const& ht) {
  ht.printToStream(os);
  return os;
}

It's normally considered bad design to declare friends, because it partly breaks encapsulation and is an even tighter coupling than inheritance. While it's mostly a matter of taste when friends' convenience surpasses the tight coupling for normal functions, it is a huge encapsulation issue when dealing with templates, because anyone can specialize the template:

template <> istream& operator>> <int, std::string> (istream& in, const Hash_Table<int,std::string>& right) 
{
  right.hashTable.resize(1);
  for (unsigned i = 0; i < 2000000; ++i)
    right.hashTable[0].push_back("I just hijacked your Hash_Table implementation!";
} 

This is evil but legal - you made that function your friend, although it might not be so friendly ;-)

Change your Hash_Table class:

template< typename T, typename K>
class Hash_Table;   // fore declaration

template< typename T, typename K>
ostream&  operaotr<< (ostream& out, Hash_Table<T,K> const& right); //foreward declaration

template <typename T,typename K>
class Hash_Table {
public:
Hash_Table(int size); 
void insert(T newEntry); 
T* search(K key); 
void delete_entry(T* entry);
// change here!!!
friend ostream& operator<< <T,K> (ostream& out, const Hash_Table& right);
private:
vector< vector<T> > hashTable;
};

the implementation if operator<< remains to be your original code. Try it ,and see if there's any more error.

Let me talk a little about the friend of a class template. A friend of a class template can be classified into three kinds:

  1. Normal class and normal function, no any template
  2. Class template and Function template
  3. Specialized class template and specialized function template

There're some examples to make it clear:

template<typename T>
class Exam
{
   friend void normalFunc();
   friend class NormalClass;
};
// nothing happen, it looks straightforward

Another example:

template<typename T>
class TemplateClass;
template<typename T>
void FunctionTemplate();

template<typename T>
class Exam
{
    template<typename U>
    friend class TemplateClass; 
    template<typename U>
    friend void FunctionTemplate();
};

This means all of the instances of the function template "FunctionTemplate" and the class template "TemplateClass" are the friend of all of the instances of the class template "Exam" Means that:

  1. TemplateClass<AnyType> is friend class of Exam<AnyOtherType>

  2. FunctionTemplate<AnyType> is friend function of Exam<AnyOtherType>

Notes that, AnyType can be the same as AnyOtherType.

Here's the most useful example, this is what you want:

    template<typename T>
    class TemplateClass;
    template<typename T>
    void FunctionTemplate();

    template<typename T>
    class Exam
    {

        friend class TemplateClass<T>; 

        friend void FunctionTemplate<T>();
    };

This means that:

  1. Only the TemplateClass<SpecificType> is friend class of Exam<SpecificType>
  2. Only the FunctionTemplate<SpecificType> is friend function of Exam<SpecificType>

By this way, you can grant the friend access priviledge more pricisely and of course more safely!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top