I got the error- keyedcollection.h(34): error C2955: 'KeyedCollection' : use of class template requires template argument list
I have searched google and other sites for hours and am still not able to find any solution to this problem. Is there any suggestions as to what I can do?
Declaration:
friend ostream& operator<<(ostream&, const KeyedCollection&);
Definition:
template <class K, class T>
ostream& operator<<(ostream& out, const KeyedCollection& e){
for (int i = 0; i < key.size(); i++){ out << key.at(i); }
return out;
}
The operator should be inside the class.
template <class K, class T>
class KeyedCollection {
public:
// Create an empty collection
KeyedCollection();
// Return the number of objects in the collection
int size() const;
void get_vectorone();
// 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& out, const KeyedCollection<K,T>& e){
for (int i = 0; i < e.key.size(); i++) { out << e.key.at(i); }
return out;
}
private:
vector<K> key;
vector<T> object;
};
template <class K, class T>
KeyedCollection<K,T>::KeyedCollection(){}
template <class K, class T>
int KeyedCollection<K,T>::size() const { return key.size(); }
template <class K, class T>
void KeyedCollection<K,T>::insert(const K& id, const T& customer){
key.push_back(id);
object.push_back(customer);
}
Related
im having trouble with this friend method upon calling the Union method an error of "class Set has no member named 'Union'. The program keep throwing an error regarding that Union function. I have no clue why does this friend declaration not work.
This is my Set class it uses a custom vector class, which is not relevant.
ifndef SET_H
#define SET_H
#include "myvector.h"
template <class T>
class Set
{
public:
Set();
virtual ~Set();
MyVector<T> & GetData();
void Push_back(const T & element);
void print();
friend void Union(const Set<T> &set1, const Set<T> &set2, Set<T> &set3);
private:
MyVector<T> data;
};
template <class T>
Set<T>::Set()
{
}
template <class T>
Set<T>::~Set()
{
}
template <class T>
MyVector<T> & Set<T>::GetData()
{
return data;
}
template <class T>
void Set<T>::Push_back(const T & element)
{
data.push_back(element);
}
template <class T>
void Set<T>::print()
{
data.print();
}
template <class T>
void Union(const Set<T> &set1, const Set<T> &set2, Set<T> &set3)
{
int i = 0, j = 0;
while(i<set1.data.count && j<set2.data.count)
{
if(set1.data[i] == set2.data[j])
{
set3.Push_back(set1.data[i]);
i++;
j++;
}
else if(set1.data[i] < set2.data[j])
{
set3.Push_back(set1.data[i]);
i++;
}
else
{
set3.Push_back(set2.data[j]);
j++;
}
}
while(i<set1.data.count)
{
set3.Push_back(set1.data[i]);
i++;
}
while(i<set2.data.count)
{
set3.Push_back(set2.data[j]);
j++;
}
}
This is my main
#include <iostream>
#include "set.h"
int main()
{
Set<int> set1;
Set<int> set2;
Set<int> set3;
set1.Push_back(1);
set1.Push_back(2);
set1.Push_back(4);
set1.Push_back(1);
set2.Push_back(3);
set2.Push_back(5);
cout << "printing set 1\n";
set1.print();
cout << "printing set 2\n";
set2.print();
set3.Union(set1,set2,set3);
cout << "printing set 3 (union)\n";
set3.print();
return 0;
}
A free union function would normally take two arguments and return the union instead of having to instantiate the container that is supposed to receive the result and pass that as a parameter to the function.
You can still do it that way, but you'll need to declare the friend function as a function template.
In these examples, I'm returning the resulting Set<T> instead. Rewriting it to take set3 as an argument instead is left as an exercice:
template <class T>
class Set
{
public:
template<typename U> // make this a declaration of a function template
friend Set<U> Union(const Set<U>& set1, const Set<U>& set2);
};
template<typename T> // define it:
Set<T> Union(const Set<T>& set1, const Set<T>& set2) {
Set<T> set3;
// fill set3
return set3;
}
Or easier: Define the friend function in your class definition directly:
template <class T>
class Set
{
public:
// Set will here be Set<T> automatically:
friend Set Union(const Set& set1, const Set& set2) {
Set set3;
// fill set3
return set3;
}
};
In main:
Set<int> set3 = Union(set1, set2);
I use Visual Studio 2019 compiler. For educational purposes I have decided to implement/create a template based FIFO queue. To achieve that I decided to inherit earlier implemented and well functioning doubly linked list (template based as well).
Here is the code which I purposefully simplified for presentation clarity purposes (I removed all the insignificant member functions declarations and definitions):
Doubly_linked_list.h :
#pragma once
#include <iostream>
#include <string.h>
using namespace std;
template <class T>
class list;
template <class T>
ostream& operator<<(ostream& out, const list<T>& arg);
template <class T>
class list
{
protected:
struct node
{
T* obj_ptr;
node* next_node_ptr;
node* previous_node_ptr;
node()
: next_node_ptr(NULL), previous_node_ptr(NULL), obj_ptr(NULL) {}
};
node* first_node_ptr;
node* last_node_ptr;
node* chosen_node_ptr;
int element_counter;
public:
list()
{
first_node_ptr = last_node_ptr = chosen_node_ptr = NULL;
element_counter = 0;
}
friend ostream& operator<< <T>(ostream& out, const list<T>& arg);
void set_chosen_after_last()
{
chosen_node_ptr = NULL;
}
void add_element(T& obj);
~list();
private:
void add_element_as_first(node* newly_added_node_ptr);
void add_element_as_last(node* newly_added_node_ptr);
void add_element_in_middle(node* newly_added_node_ptr);
};
//##################################################################################
//##################################################################################
template <class T>
list<T>::~list()
{
if (!first_node_ptr)
return;
node* bishop;
int i;
cout << "\n\n";
for (chosen_node_ptr = first_node_ptr, i = 0; chosen_node_ptr; i++)
{
bishop = chosen_node_ptr->next_node_ptr;
delete chosen_node_ptr;
chosen_node_ptr = bishop;
}
}
template <class T>
ostream& operator<<(ostream& out, const list<T>& arg)
{
if (!(arg.first_node_ptr))
return out;
typename list<T>::node* chaser = arg.first_node_ptr;
for (; chaser; chaser = chaser->next_node_ptr)
{
out << *(chaser->obj_ptr) << "\t";
}
return out;
}
template <class T>
void list<T>::add_element_in_middle(node* newly_added_node_ptr)
{
node* previous_node = chosen_node_ptr->previous_node_ptr;
previous_node->next_node_ptr = newly_added_node_ptr;
newly_added_node_ptr->previous_node_ptr = previous_node;
newly_added_node_ptr->next_node_ptr = chosen_node_ptr;
chosen_node_ptr->previous_node_ptr = newly_added_node_ptr;
chosen_node_ptr = newly_added_node_ptr;
}
template <class T>
void list<T>::add_element_as_last(node* newly_added_node_ptr)
{
last_node_ptr->next_node_ptr = newly_added_node_ptr;
newly_added_node_ptr->previous_node_ptr = last_node_ptr;
last_node_ptr = newly_added_node_ptr;
}
template <class T>
void list<T>::add_element_as_first(node* newly_added_node_ptr)
{
if (!first_node_ptr)
{
first_node_ptr = newly_added_node_ptr;
last_node_ptr = newly_added_node_ptr;
}
else
{
newly_added_node_ptr->next_node_ptr = first_node_ptr;
first_node_ptr->previous_node_ptr = newly_added_node_ptr;
first_node_ptr = newly_added_node_ptr;
chosen_node_ptr = first_node_ptr;
}
}
template <class T>
void list<T>::add_element(T& obj)
{
node* new_node_ptr = new node;
new_node_ptr->obj_ptr = &obj;
if (!first_node_ptr || chosen_node_ptr == first_node_ptr)
add_element_as_first(new_node_ptr);
else
{
if (!chosen_node_ptr)
{
add_element_as_last(new_node_ptr);
}
else
{
add_element_in_middle(new_node_ptr);
}
}
element_counter++;
}
Queue.h :
#pragma once
#include "Doubly_linked_list.h"
template <class t>
class queue;
template <class T>
ostream& operator<<(ostream& out, typename const queue<T>& arg);
template <class T>
class queue : private list<T>
{
public:
void push(T arg)
{
list<T>::set_chosen_after_last();
list<T>::add_element(arg);
}
friend ostream& operator<< <> (ostream& out, typename const queue<T>& arg);
};
template <class T>
ostream& operator<<(ostream& out, typename const queue<T>& arg)
{
if (!(arg.list<T>::first_node_ptr))
return out;
typename list<T>::node* chaser = arg.first_node_ptr;
for (; chaser; chaser = chaser->next_node_ptr)
{
out << *(chaser->obj_ptr) << "\t";
}
return out;
}
Main.cpp :
#include <iostream>
#include "Queue.h"
int main()
{
queue<int> ex1;
ex1.push(5);
cout << ex1;
}
As a result of testing the above code I was expecting the number 5 to be printed on the console, the result is however some random integer number (different each time I run this code) like this one:
7599868
I started debugging my code and noticed that arg, being rhs argument for overloaded operator<< and also being the reference to ex1 object, somehow has its obj_ptr pointing at integer object of value different than 5 inside the overloaded operator body. Instead the value is the random one eventually printed on the console as you can see on below screen shot from the debugger mode:
Debugger_mode_screen_shot.png
I am now running out of ideas on the possible root cause of such a behavior. To my knowledge arg should refer to the exact same object in memory as ex1, hence their obj_ptr pointers should point at the exact same object of type T (integer in this case) and of the exact same value (5 in this case). Although this is not what actually happens. I have read through numerous topics here on SO and could not find any of them that would address this particular situation/issue.
What is even more interesting and leading me to a greater confusion is the fact that I have tried to recreate this issue by writing a separate simple code imitating the inheritance mechanisms used in the original code. Here however the results are totally as expected - reference to an inherited template class object is being passed to the overloaded operator correctly (with the correct value of integer object pointed at by ptr_a pointer) and hence the console eventually prints out the correct value:
#include <iostream>
#include <string.h>
using namespace std;
template <class T>
class Base;
template <class T>
ostream& operator<<(ostream& out, Base<T>& arg);
template <class T>
class Base
{
protected:
struct node
{
T* ptr_a;
node* next_node_ptr;
node()
{
ptr_a = new T;
next_node_ptr = NULL;
}
};
node* first_node_ptr;
public:
Base()
{
first_node_ptr = new node;
*(first_node_ptr->ptr_a) = 5;
}
friend ostream& operator<< <> (ostream& out, Base<T>& arg);
};
template <class t>
ostream& operator<<(ostream& out, Base<t>& arg)
{
cout << "this is " << *arg.first_node_ptr->ptr_a << endl;
return out;
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
template <class T>
class Deriv;
template <class T>
ostream& operator<<(ostream& out, const Deriv<T>& arg);
template <class T>
class Deriv : private Base<T>
{
public:
void new_function() {}
friend ostream& operator<< <> (ostream& out, const Deriv& arg);
};
template <class T>
ostream& operator<<(ostream& out, const Deriv<T>& arg)
{
cout << "This is " << *arg.first_node_ptr->ptr_a << endl;
return out;
}
int main()
{
Base<int> ex1;
cout << ex1;
Deriv<int> ex2;
cout << ex2;
}
Output:
this is 5
This is 5
It is worth mentioning that the overloading operator<< worked perfectly fine for list < T > when I originally implemented it. Also I tried to use Code::Blocks to test this code but the issue persisted there as well. As you can also see I befriended operator<< by first forward declaring it before implementing the actual template class definition (to let the friendship always be constituted for a given type parameter particularly and not for all possible types at once). This method has worked perfectly fine for me in list < T > and in all the previous similar codes.
Can any of you guys point out a possible root cause of this situation and what exactly I should do now to make it work as expected (in this case to print 5 instead of some random number)? Thank you in advance for any ideas.
This code stores a pointer to the object referred to by obj.
template <class T>
void list<T>::add_element(T& obj)
{
node* new_node_ptr = new node;
new_node_ptr->obj_ptr = &obj;
...
This code calls list<T>::add_element with a reference to a local object, namely arg.
void push(T arg)
{
list<T>::set_chosen_after_last();
list<T>::add_element(arg);
}
Once push has exited the pointer stored by add_element is invalid. This explains the garbage value you see when you later use the pointer.
The solution is not to store pointers in your nodes but to copy or move the objects passed to your list and queue functions to your nodes.
I have a Vector class and I overload the operator*
I would like to be able to multiply a Vector of float with a Vector of int.
I have the following code but when I compile him, I have an error because I don't have access to private fields.
template <class T>
class Vecteur
{
template <class U> friend class Vecteur;
private:
int m_dimensions;
T *m_values;
}
template<class T1, class T2>
T1 operator*(const Vecteur<T1> &v1, const Vecteur<T2> &v2)
{
assert(v1.m_dimensions == v2.m_dimensions);
T res = T();
for (int i = 0; i < v1.m_dimensions; i++)
{
res += v1.m_values[i] * v2.m_values[i];
}
return res;
}
I also tried this but I can access to private fields of v1 but not to the private fields of v2
template <class T>
class Vecteur
{
private:
int m_dimensions;
T *m_values;
template<class T2>
friend T operator*(const Vecteur<T> &v1, const Vecteur<T2> &v2)
{
assert(v1.m_dimensions == v2.m_dimensions);
T res = T();
for (int i = 0; i < v1.m_dimensions; i++)
{
res += v1.m_values[i] * v2.m_values[i];
}
return res;
}
}
Your first version declares one specialization of Vecteur a friend of another. This doesn't help your operator *, since this is still not a friend and can't access private members.
Add proper friend declaration for template overload in your Vecteur (and you do not need to friend the specialization):
template<class T>
class Vectuer {
//...
template<class T1, class T2> std::common_type_t<T1, T2>
friend operator*(const Vecteur<T1>& , const Vectuer<T2>& );
//...
};
// And than a definition after the declaration
Alternatively, you can friend the specialization, and add operator* as a member, but I do not like this, since such overloaded operators are more cleanly implemented as freestanding functions.
When you have the urge to declare a function or a class a friend of a class, take moment to look at your design and ask yourself whether that is absolutely necessary.
In the case of the posted code, instead of trying to solve the problem associated with granting friend-ship to the operator* function, provide accessor functions to the data of the class and get rid of the need for granting friend-ship altogether.
template <class T>
class Vecteur
{
public:
int getDimensions() const { return m_dimensions; };
T& operator[](std::size_t i) { return m_values[i]; };
T const& operator[](std::size_t i) const { return m_values[i]; };
private:
int m_dimensions;
T *m_values;
};
// Does not require to be a friend of the class.
template<class T1, class T2>
typename std::common_type<T1, T2>::type operator*(const Vecteur<T1> &v1, const Vecteur<T2> &v2)
{
assert(v1.getDimensions() == v2.getDimensions());
typename std::common_type<T1, T2>::type res{};
for (int i = 0; i < v1.getDimensions(); i++)
{
res += v1[i] * v2[i];
}
return res;
}
I've recently learned that there are two ways to declare a template friend class or function. For example, to declare a template friend class, you may do this
template <typename T>
class goo
{
template <typename T>
friend class foo;
};
or this
template <typename T>
class goo
{
friend class foo <T>;
};
These two declarations are in fact different. The former allows you to use any type of template friend class foo with any type of template friend class goo. Where as the latter only allows you to use the same type such that you may do foo<int> with goo<int> but not foo<int> with goo<char>.
In the header file below, I try to use the latter form of the declaration to make my template friend function friend std::ostream& operator<<(std::ostream&, const Array<T>&); more type-specific in an effort to make my program more encapsulated.
//ARRAY_H
#include <iostream>
#include "Animal.h"
const int DefaultSize = 3;
template <typename T> // declare the template and the paramenter
class Array // the class being parameterized
{
public:
Array(int itsSize = DefaultSize);
Array(const Array &rhs);
~Array() { delete[] pType; }
// operators
Array& operator=(const Array&);
T& operator[](int offSet) { return pType[offSet]; }
const T& operator[](int offSet) const { return pType[offSet]; }
// accessors
int GetSize() const { return itsSize; }
// friend function
friend std::ostream& operator<< <T>(std::ostream&, const Array<T>&);
private:
T *pType;
int itsSize;
};
template <typename T>
Array<T>::Array(int size = DefaultSize) :itsSize(size)
{
pType = new T[size];
for (int i = 0; i < size; i++)
pType[i] = static_cast<T>(0);
}
Array<Animal>::Array(int AnimalArraySize) :itsSize(AnimalArraySize)
{
pType = new Animal[AnimalArraySize];
}
template <typename T>
Array<T>::Array(const Array &rhs)
{
itsSize = rhs.GetSzie();
pType = new T[itsSize];
for (int i = 0; i < itsSize; i++)
pType[i] = rhs[i];
}
template <typename T>
Array<T>& Array<T>::operator=(const Array &rhs)
{
if (this == &rhs)
return *this;
delete[] pType;
itsSize = rhs.GetSize();
pType = new T[itsSize];
for (int i = 0; i < itsSize; i++)
pType[i] = rhs[i];
return *this;
}
template <typename T>
std::ostream& operator<<(std::ostream& output, const Array<T> &theArray)
{
for (int i = 0; i < theArray.GetSize(); i++)
output << "[" << i << "]" << theArray[i] << std::endl;
return output;
}
#endif
However, I receive a compiler error "error C2143: syntax error : missing ';' before '<'" for line 23 which is friend std::ostream& operator<< <T>(std::ostream&, const Array<T>&);.
When using the former form of the declaration by changing line 23 to this
template <typename T>
friend std::ostream& operator<<(std::ostream&, const Array<T>&);
My program executes without any errors.
I assume I cannot use the same syntax from type-specific template friend classes for type-specific template friend functions, or that I may be missing some kind of forward declaration. I've searched through stack-overflow and the closest topic I could find for this problem is here, but they only discuss type-specific template friend classes. I am unable to find a topic that discusses the correct syntax for using a template friend function in this way.
If this is a syntax error, what is the correct way to declare my type-specific template friend function? If this is not a syntax error, why will my program not compile?
Here are the rest of my project files for your reference. The desired behavior of my program is to show how a parametrized array uses a template to create multiple instances of different array types.
//ANIMAL_H
#ifndef ANIMAL_H
#define ANIMAL_H
#include <iostream>
class Animal
{
public:
// constructors
Animal();
Animal(int);
~Animal();
// accessors
int GetWeight() const { return itsWeight; }
void SetWeight(int theWeight) { itsWeight = theWeight; }
// friend operators
friend std::ostream& operator<<(std::ostream&, const Animal&);
private:
int itsWeight;
};
#endif
//ANIMAL.CPP
#include "Animal.h"
#include <iostream>
Animal::Animal() :itsWeight(0)
{
std::cout << "animal() ";
}
Animal::Animal(int weight) : itsWeight(weight)
{
std::cout << "animal(int) ";
}
Animal::~Animal()
{
std::cout << "Destroyed an animal...";
}
std::ostream& operator<<(std::ostream& theStream, const Animal& theAnimal)
{
theStream << theAnimal.GetWeight();
return theStream;
}
//MAIN.CPP
#include <iostream>
#include "Animal.h"
#include "Array.h"
void IntFillFunction(Array<int>& theArray);
void AnimalFillFunction(Array<Animal>& theArray);
int main()
{
Array<int> intArray;
Array<Animal> animalArray;
IntFillFunction(intArray);
AnimalFillFunction(animalArray);
std::cout << "intArray...\n" << intArray;
std::cout << "\nanimalArray...\n" << animalArray << std::endl;
std::cin.get();
return 0;
}
void IntFillFunction(Array<int>& theArray)
{
bool Stop = false;
int offset, value;
while (!Stop)
{
std::cout << "Enter an offset (0-9) and a value. ";
std::cout << "(-1 to stop): ";
std::cin >> offset >> value;
if (offset < 0)
break;
if (offset > 9)
{
std::cout << "***Please use values between 0 and 9.***\n";
continue;
}
theArray[offset] = value;
}
}
void AnimalFillFunction(Array<Animal>& theArray)
{
Animal *pAnimal;
for (int i = 0; i < theArray.GetSize(); i++)
{
pAnimal = new Animal(i * 10);
theArray[i] = *pAnimal;
delete pAnimal;
}
}
You need to declare the function template before you refer to a specialization as a friend.
// Forward declare class template.
template <typename T> class Array;
// Declare function template.
template <typename T>
std::ostream& operator<<(std::ostream& os, const Array<T>& arr);
template <typename T>
class Array
{
//...
friend std::ostream& operator<< <>(
std::ostream& os, const Array<T>& arr);
//...
};
You need a forward declaration of the function template (just as you need with a class template) in order to friend a specialization. Your code should be:
template <typename T>
std::ostream& operator<<(std::ostream& output, const Array<T> &theArray);
template <typename T>
class Animal
{
// ...
friend std::ostream& operator<< <T>(std::ostream&, const Array<T>&);
};
I cant understand a behavior of operator<< in my class:
header:
#ifndef VECTOR_H_
#define VECTOR_H_
#include <string>
#include <iostream>
template<class T>
class Vector {
static const int EXPANDER = 10;
T* array;
int next;
int length;
void expand();
void contract();
public:
Vector();
Vector(const Vector& v);
void add(const T e);
T get(int index) const;
bool removeByIndex(int index);
bool remove(T e);
int size() const;
T operator[](int i) const;
T& operator+=(const T& t);
T operator+(const T& s);
friend std::ostream& operator<< (std::ostream& os, const Vector<T>& obj);
friend std::istream& operator>> (std::istream& is, Vector<T>& obj);
std::string toString();
~Vector();
};
#endif /* VECTOR_H_ */
vector.cpp
#include "Vector.h"
#include <string>
#include <sstream>
template<class T>
Vector<T>::Vector() {
length = EXPANDER;
next = 0;
array = new T[EXPANDER];
}
template<class T>
Vector<T>::Vector(const Vector& v) {
length = v.next + 1 + EXPANDER;
next = v.next;
array = new T[length];
for (int i = 0; i <= v.next; i++) {
array[i] = v.array[i];
}
}
template<class T>
void Vector<T>::add(const T e) {
if (next >= length - 1)
expand();
array[next++] = e;
}
template<class T>
T Vector<T>::get(int index) const {
if (index > next)
return -1;
return array[index - 1];
}
template<class T>
bool Vector<T>::removeByIndex(int index) {
if (index > next)
return false;
for (int i = index; i < length; i++) {
array[i] = array[i + 1];
}
next--;
contract();
return true;
}
template<class T>
bool Vector<T>::remove(T e) {
int index = -1;
for (int i = 0; i < next; i++) {
if (array[i] == e) {
index = i;
break;
}
}
if (index == -1)
return false;
return removeByIndex(index);
}
template<class T>
int Vector<T>::size() const {
return next;
}
template<class T>
void Vector<T>::expand() {
length += EXPANDER;
T* temp = new T[length];
for (int i = 0; i < next; i++) {
temp[i] = array[i];
}
delete[] array;
array = temp;
}
template<class T>
void Vector<T>::contract() {
if (next + EXPANDER >= length)
return; // NO need to contract
length = next + EXPANDER + 1;
T* temp = new T[length];
for (int i = 0; i < next; i++) {
temp[i] = array[i];
}
delete[] array;
array = temp;
}
template<class T>
T Vector<T>::operator[](int i) const {
return get(i);
}
template<class T>
T& Vector<T>::operator+=(const T& t) {
for (int i = 0; i < t.size(); i++) {
add(t.get(i));
}
return *this;
}
template<class T>
T Vector<T>::operator+(const T& s) {
this += s;
return this;
}
template<class T>
std::ostream& operator<< (std::ostream& os, Vector<T>& obj) {
os << obj.toString();
return os;
}
template<class T>
std::istream& operator>> (std::istream& is, Vector<T>& obj) {
int size;
T temp;
is >> size;
for (int i = 0; i < size; i++) {
is >> temp;
add(temp);
}
return is;
}
template<class T>
std::string Vector<T>::toString() {
using namespace std;
ostringstream sb;
sb << "Elements(" << size() << "): [";
for (int i = 0; i < next; i++) {
sb << array[i] << ", ";
}
string r;
r = sb.str();
r = r.substr(0, r.size() - 2) + string("]");
return r;
}
template<class T>
Vector<T>::~Vector() {}
and i run this code with main.cpp
#include "Vector.h"
#include "Vector.cpp"
#include <string>
#include <iostream>
using namespace std;
int main() {
Vector<int> v;
v.add(1);
v.add(2);
cout << v << endl;
}
the magic is in operator<< declaration in header. if i delete CONST modifier, compiler says: Undefined reference to operator<<, but with const it works. It is interesting that in my implementation, in cpp, I doesn't have CONST.
btw, how to solve warnings with warning: friend declaration declares a non-template function for operators?
You should learn how to boil this down to a Short, Self-Contained, Compilable Example aka Minimal Working Example.
Here's an SSCCE that demonstrates the problem:
#include <iostream>
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
T get() const { return m; }
};
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T>& v)
{
// accessing a private member leads to a compiler error here:
return o << "[function template]" << /*v.m*/ v.get();
}
// remove this function to get the same behaviour as in the OP
std::ostream& operator<<(std::ostream& o, Vector<int> const& v)
{
return o << "function" << v.m;
}
int main()
{
Vector<int> v(42);
std::cout << v;
}
Note that it's only about 30 lines long and fits onto one screen w/o scroll bars.
Now, the problem is based upon the friend declaration inside your class template:
friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
This looks up a function named operator<< in the surrounding scopes, to befriend this already existing function. But it doesn't find any that matches those parameter type. Therefore, it declares a new function in the surrounding (= global) namespace. This function looks like this:
std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
(in the global namespace)
Note: it can only be found via Argument-Dependent Lookup if it's only declared via a friend-declaration.
Now, you later declare a function template of the same name. But the compiler cannot know that you meant to befriend this function template when you wrote the friend declaration inside you class template before. So those two, the friend function and the function template, are unrelated.
What happens now is the usual overload resolution. The function template is preferred if you don't add a const, since you call it with a non-const argument:
Vector<int> v;
v.add(1);
v.add(2);
cout << v << endl; // v is not const
for this argument of type Vector<int>, the binding to Vector<int>& of the function template (specialization) is preferred over the binding to the Vector<int> const& of the friend function. Hence, the function template is chosen, which has a definition (function body) and everything compiles, links and works. Note that the function template is not befriended, but this doesn't raise an error since you don't use any private members.
Once you add the const to the function template, the function template is no longer a better match for the argument. As we have a function and a function template with the same overload "rank", the non-template is preferred. Ergo, the friend function is called, which has no definition => a linker error occurs.
The simplest solution is to define the friend function inside the class definition:
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
};
A solution using forward-declarations:
template<class T>
class Vector;
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
friend std::ostream& operator<< <T>(std::ostream& o, Vector<T> const& v);
};
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
Now, the compiler can find the forward-declared function template and befriend this existing function (the specialization of the function template) instead of declaring a new function.
A solution befriending the whole function template:
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
template<class U>
friend std::ostream& operator<<(std::ostream& o, Vector<U> const& v);
};
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
In this solution, the friend-declaration declares a function template, and the later declaration at namespace scope following the class' definition redeclares this function template.