-1

I have a template class called "KeyedCollection" that contains functions to insert data into a vector, as well as stream out the data. The vector is a private member function. I can't seem to figure out how to use the information from this vector in my overloading ostream friend function. Note: I cannot change the general structure of the class and the function arguments, they have to stay as they are. I list all of the class for reference, but the function in question is the last one.

#include "stdafx.h"
#include <iostream>
#include <vector>
#include "Windows.h"
#include <string>

using namespace std;

template <class K, class T> 
class KeyedCollection {
public:
  // Create an empty collection
  KeyedCollection();

  // Return the number of objects in the collection
  int size() const;

  // Insert object of type T with a key of type K into the
  // collection using an “ignore duplicates” policy
  void insert(const K&, const T&);

  // Output data value of objects in the collection,
  // one data value per line
  friend ostream& operator<<(ostream&,
                             const KeyedCollection&);

private:
  // Insert required members here
        int objSize;
vector<T> objects;

};

template<class K, class T>
KeyedCollection<K,T>::KeyedCollection() {

objSize = 0;
vector<T> objects;
}   

template<class K, class T>
int KeyedCollection<K,T>::size() const {

    objSize = objects.size();

return objSize;
 }

template<class K, class T> 
void KeyedCollection<K,T>::insert(const K&,const T& c) {

objects.push_back(c);

}
// !!! function i am trying to define !!!
template<class K, class T>
ostream& operator<<(ostream& outstream,const KeyedCollection<K,T>& inst) {

outstream<<inst<<endl;

return outstream;
}

Also, I'm getting an error that says

"fatal error LNK1120: 1 unresolved externals"

and one that says

"error LNK2019: unresolved external symbol "class std::basic_ostream > & __cdecl operator<<(class std::basic_ostream > &,class KeyedCollection const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABV?$KeyedCollection@HVCustomer@@@@@Z) referenced in function _main" ...

Just as a side question, any idea what those could be?

jordpw
  • 181
  • 2
  • 16
  • Move implementation of the friend `<<` into the body of the class and does the error go away or be replaced with a different one? – Yakk - Adam Nevraumont Jan 31 '14 at 03:19
  • okay i tried that, but i dont think i did it correctly...would you define the function as ostream& KeyedCollection::operator<<(ostream& outstream,const KeyedCollection& inst) { outstream< – jordpw Jan 31 '14 at 03:28
  • In the body of the class. Instead of the `;` at the end of the `friend` declaration put a `{` then write the body then put a `}`. Newlines optional. – Yakk - Adam Nevraumont Jan 31 '14 at 03:29
  • Still doesn't work, just returns more errors – jordpw Jan 31 '14 at 03:34
  • Different errors? By and chance is the above code split between header and cpp file? Are the errors after my change a subset of the errors before my change? What is the error after my change? Did not work is singularly unhelpful. – Yakk - Adam Nevraumont Jan 31 '14 at 03:41
  • Yes different errors, although I changed it back to a friend function because I am required to keep it as such. The errors were totally different, not subsets as far as I am aware. The above code is one file – jordpw Jan 31 '14 at 03:58

1 Answers1

0

cppreference and Johannes Schaub - litb both provide the same method for getting this to work.

You want to make one single instance (called "specialization" in generic terms) of that template a friend. You do it the following way [...]

First make a forward declaration before the definition of your class:

template <class K, class T> class KeyedCollection;

template<class K, class T>
ostream& operator<<(ostream& outstream,const KeyedCollection<K,T>& inst);

Because the compiler knows from the parameter list that the template arguments are T and U, you don't have to put those between <...>, so they can be left empty.

Then make your friend declaration and be sure to add <> after operator<<:

template <class K, class T> 
class KeyedCollection {
public:

// snip

friend ostream& operator<< <> (ostream& outstream,const KeyedCollection<K,T>& inst);

// snip

};

Finally you can define it:

template<class K, class T>
ostream& operator<<(ostream& outstream,const KeyedCollection<K,T>& inst) {

// Just an example
for (const auto& t : inst.objects)
{
    std::cout << t << std::endl;
}

return outstream;
}

Live Example


Alternately, do what Yakk suggested.

template <class K, class T> 
class KeyedCollection {
public:

// snip

friend ostream& operator<<(ostream& outstream,const KeyedCollection<K,T>& inst) {

for (const auto& t : inst.objects)
{
    std::cout << t << std::endl;
}

return outstream;
}

// snip

};

Live Example

Community
  • 1
  • 1
  • This helped!! It actually ran for once, but...it caused a stack overflow. is there anything you can think of in this code that would cause that? – jordpw Jan 31 '14 at 04:04
  • @jordpw Hm, I guess whatever caused the stackoverflow would be in your `main` code, because clearly the stackoverflow does not occur in the live examples. –  Jan 31 '14 at 04:07
  • Okay, i changed parts of the main routine and that worked. Thanks for your help. – jordpw Jan 31 '14 at 04:15