C ++ - How to declare friend function template for class template

I have a class template that will list the objects stored in the array. I get the following error, and I am confused when the error occurs due to an error in the .obj and .exe files.

1 unresolved external (proj08.exe line 1)
unresolved external symbol "class std :: basic_ostream> and the __cdecl <operator (class std :: basic_ostream> &, class MyVector)" (?? 6 @YAAAV? $ basic_ostream @DU? $ char_traits @D @std @@@ std @ @ AAV01 @V? $ MyVector @N @@@ Z) link to the _main function (line porj08.obj 1)

proj08.cpp

#include "stdafx.h" #include <string> #include "MyVector.h" const double FRACTION = 0.5; int main() { cout << "\nCreating a vector of doubles named Sam\n"; MyVector<double> sam; cout << "\nPush 12 values into the vector."; for (int i = 0; i < 12; i++) sam.push_back(i + FRACTION); cout << "\nHere is sam: "; cout << sam; cout << "\n---------------\n"; cout << "\nCreating an empty vector named joe"; MyVector<double> joe; // test assignment joe = sam; cout << "\nHere is joe after doing an assignment:\n "; cout << joe; cout << "\n---------------\n"; // test the copy constructor MyVector<double> bill = sam; cout << "\nHere is bill after creating it using the copy constructor:\n "; cout << bill; cout << "\n---------------\n"; cout << endl; system("PAUSE"); return 0; } 

Myvector.h

 #pragma once #include <iostream> #include "stdafx.h" using namespace std; template <class T> class MyVector { private: int vectorSize; int vectorCapacity; T *vectorArray; public: MyVector() { vectorArray = new T[10]; } T size(); T capacity(); void clear(); void push_back(T n); T at(int n); friend ostream& operator<<(ostream& os, MyVector<T> vt); MyVector<T> operator=(MyVector<T>&); }; /* * TEMPLATE FUNCTIONS */ //Return array size template<class T> T MyVector<T>::size() { return vectorSize; } // Return array capacity template<class T> T MyVector<T>::capacity() { return vectorCapacity; } // clear array values template<class T> void MyVector<T>::clear() { for (int i = 0; i < vectorSize; i++) { vectorArray[i] = '\0'; } vectorSize = 0; vectorCapacity = 2; } // Add number to array and double array size if needed template<class T> void MyVector<T>::push_back(T n) { int test = 100; if (vectorCapacity > vectorSize) { vectorArray[vectorSize] = n; vectorSize++; } else { if (vectorCapacity == 0) { vectorArray = new T[4]; vectorArray[0] = n; vectorCapacity = 4; vectorSize++; } else { int newCapacity = vectorCapacity * 2; // Dynamically allocate a new array of integers what is somewhat larger than the existing array.An algorithm that is often used is to double the size of the array. int *tempArray = new int[newCapacity]; // Change capacity to be the capacity of the new array. vectorCapacity = newCapacity; // Copy all of the numbers from the first array into the second, in sequence. for (int i = 0; i < MyVector::size(); i++) { tempArray[i] = vectorArray[i]; } delete[] vectorArray; vectorArray = new T[newCapacity]; for (int i = 0; i < MyVector::size(); i++) { vectorArray[i] = tempArray[i]; } delete[] tempArray; // Add the new element at the next open slot in the new array. vectorArray[vectorSize] = n; // Increment the size; vectorSize++; } } } // Return Value and given point in array template<class T> T MyVector<T>::at(int n) { return vectorArray[n]; } // Set one vector to equil another template<class T> MyVector<T> MyVector<T>::operator=(MyVector<T>& right) { if (vectorCapacity < right.vectorCapacity) { if (vectorCapacity != 0) delete[] vectorArray; vectorArray = new T[right.vectorCapacity]; vectorCapacity = right.vectorCapacity; } vectorSize = right.size(); // Assign values from left to right for (int i = 0; i < vectorSize; i++) { vectorArray[i] = right.at(i); } return *this; } // Cout Vector template<class T> ostream& operator << (ostream& os, MyVector<T> vt) { T size = vt.size(); for (T i = 0; i < size; i++) { os << "index " << i << " is " << vt.at(i) << endl; } return os; } 
+2
source share
2 answers

You must declare friend as a function template if you want to match the one you defined:

 template <typename U> // use U, so it doesn't clash with T friend ostream& operator<<(ostream& os, MyVector<U> vt); 

If a friend function is declared for a class template, this does not make it a function template.

+6
source

The answer to @LogicStuff is absolutely right. I would like to clarify what exactly is happening in your code and how you can avoid this by using an alternative, since I believe that most C ++ programmers have encountered this problem at least once. Basically, when a template is created, let's say

 MyVector<int> something; 

then the friend declaration is automatically limited to the type of the template, in this case int , so the compiler generates

 friend ostream& operator<<(ostream& os, MyVector<int> vt); 

However, this is just an announcement. Last definition

 template<class T> ostream& operator << (ostream& os, MyVector<T> vt) 

has nothing to do with what exists for int , but because the first is a better match, whenever you try to execute

 cout << something; 

the compiler is trying to call the int version (which has no definition). This way you get a linker error.

Alternatively, it is widely used to define your statement embedded in a class, for example

 friend ostream& operator << (ostream& os, MyVector<T> vt) { T size = vt.size(); for (T i = 0; i < size; i++) { os << "index " << i << " is " << vt.at(i) << endl; } return os; } 

Now each instance of your MyVect creates the correct operator<< definition, limited to the corresponding template type. Note that the statement itself is not a member function , and it appears in the global namespace only through Argument Dependent Lookup (ADL) . This trick is called injection of a friendโ€™s name, which is widely used in the Barton-Nackman trick , and you can successfully use it, because in a call like

 cout << something; 

the call is transferred to

 operator<< (std::cout, something) 

and becuase something is of type MyVector<int> , the definition of operator<< is through ADL. If your operator<< accepts, for example, a int as the second parameter, it will not be found through ADL, since the fundamental types do not have an associated namespace.

+4
source

Source: https://habr.com/ru/post/1270951/


All Articles