How Do We Declare a Friend Function with a Class Template into .H File and Define Them into a .Cpp File (Not All in One Header File)

How do we declare a friend function with a class template into .h file and define them into a .cpp file (not all in one header file)?

There are two problems with your code snippet.

The first problem is that you've put the implementation in the source file instead of the header file. So to solve this just move the implementation into the header file.

The second problem is that even if you move the implementation into the source file the program will still not work(Demo). This is because the friend declaration that you currently have(for overloaded opearator<<), is for an ordinary(non-template) function. That is, in your original code operator<< for class template Property<> is not function template, but “ordinary” function instantiated with the class template if needed. It is what we call a templated entity.

But the definition that you've provided in the source file(.cpp) for the overloaded operator<< is for a function template and not for an oridnary function. Thus, for the statement std::cout << num << "\n"; the linker cannot find the definition/implementation corresponding to the ordinary overloaded operator<< for which you had the friend declaration.

There are two ways to solve this:

Method 1

Add a separate parameter clause in the friend declaration.

template <class PropertyType>
class Property {
PropertyType m_property;
public:
const PropertyType& operator=(const PropertyType& value);
template<typename T> //parameter cluase added here
//---------------------------------------------------vvvvv----------------------->const added here
friend std::ostream& operator<<(std::ostream& os,const Property<T>& other);
};
template <class PropertyType>
//----------------------------------------vvvvv---------------------------------->const added here
std::ostream& operator<<(std::ostream& os,const Property<PropertyType>& other) {
os << other.m_property;
return os;
}

Demo

Method 2

Here we provide forward declaration for the overloaded operator<<.

//forward declaration for class template Property
template<typename T> class Property;

//forward declaration for overloaded operator<<
template<typename T> std::ostream& operator<<(std::ostream&,const Property<T>&);//note the const in the second parameter
template <class PropertyType>
class Property {
PropertyType m_property;
public:
const PropertyType& operator=(const PropertyType& value);
//---------------------------------vvvvvvvvvvvvvv---------------------------------> angle brackets used here
friend std::ostream& operator<<<PropertyType>(std::ostream& os,const Property<PropertyType>& other);//also note the const in the second parameter
};
template <class PropertyType>
const PropertyType& Property<PropertyType>::operator=(const PropertyType& value) {
m_property = value;
return m_property;
}

template <class PropertyType>
//----------------------------------------vvvvv---------------------------------->const added here
std::ostream& operator<<(std::ostream& os,const Property<PropertyType>& other) {
os << other.m_property;
return os;
}

Demo

Method 3

If you want to provide the implementation inside the source file instead of the header file, then you should add

template std::ostream& operator<<(std::ostream& os, Property<int>& other);

inside the source file in addition to adding a template parameter clause for the friend declaration as shown below:

class.h

#ifndef MYCLASS_H
#define MYCLASS_H
#include <iostream>
template <class PropertyType>
class Property {
PropertyType m_property;
public:
const PropertyType& operator=(const PropertyType& value);
template<typename T> //parameter clause added
//---------------------------------------------------vvvvv--------------------->const added here
friend std::ostream& operator<<(std::ostream& os,const Property<T>& other);
};

#endif

class.cpp

#include "class.h"

template <class PropertyType>
const PropertyType& Property<PropertyType>::operator=(const PropertyType& value) {
m_property = value;
return m_property;
}

template<typename PropertyType>
//----------------------------------------vvvvv------->const added here
std::ostream& operator<<(std::ostream& os,const Property<PropertyType>& other) {
os << other.m_property;
return os;
}
template class Property<int>;
template std::ostream& operator<<(std::ostream& os,const Property<int>& other);

main.cpp


#include <iostream>

#include "class.h"
int main() {
Property<int> num;
num = 100;
std::cout << num << "\n";
}

Demo

The changes that I made include:

  1. Added a separate template parameter clause for the friend declaration. This is so that the friend declaration is for a function template. Moreover, we specify a different type parameter named T and not PropertyType because otherwise the new PropertyTypewill shadow the outerPropertyType`.

  2. Added a low-level const to the second parameter of the overloaded opeartor<<.

  3. In method3, inside source file(class.cpp), added

template std::ostream& operator<<(std::ostream& os,const Property<int>& other);

for the non-member function overloaded operator<<.

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

You have to 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, that does not make it a function template.

Why can templates only be implemented in the header file?

Caveat: It is not necessary to put the implementation in the header file, see the alternative solution at the end of this answer.

Anyway, the reason your code is failing is that, when instantiating a template, the compiler creates a new class with the given template argument. For example:

template<typename T>
struct Foo
{
T bar;
void doSomething(T param) {/* do stuff using T */}
};

// somewhere in a .cpp
Foo<int> f;

When reading this line, the compiler will create a new class (let's call it FooInt), which is equivalent to the following:

struct FooInt
{
int bar;
void doSomething(int param) {/* do stuff using int */}
}

Consequently, the compiler needs to have access to the implementation of the methods, to instantiate them with the template argument (in this case int). If these implementations were not in the header, they wouldn't be accessible, and therefore the compiler wouldn't be able to instantiate the template.

A common solution to this is to write the template declaration in a header file, then implement the class in an implementation file (for example .tpp), and include this implementation file at the end of the header.

Foo.h

template <typename T>
struct Foo
{
void doSomething(T param);
};

#include "Foo.tpp"

Foo.tpp

template <typename T>
void Foo<T>::doSomething(T param)
{
//implementation
}

This way, implementation is still separated from declaration, but is accessible to the compiler.

Alternative solution

Another solution is to keep the implementation separated, and explicitly instantiate all the template instances you'll need:

Foo.h

// no implementation
template <typename T> struct Foo { ... };

Foo.cpp

// implementation of Foo's methods

// explicit instantiations
template class Foo<int>;
template class Foo<float>;
// You will only be able to use Foo with int or float

If my explanation isn't clear enough, you can have a look at the C++ Super-FAQ on this subject.

Storing C++ template function definitions in a .CPP file

The problem you describe can be solved by defining the template in the header, or via the approach you describe above.

I recommend reading the following points from the C++ FAQ Lite:

  • Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?
  • How can I avoid linker errors with my template functions?
  • How does the C++ keyword export help with template linker errors?

They go into a lot of detail about these (and other) template issues.

Declare non-template function in a template class?

You might use private inheritance instead of friendship:

// class.h
#include <iostream>

class B_helper
{
protected:
static void modify(int &v);
};

template <typename T>
struct B : private B_helper
{
T value;
int value2;
B() : value2(1) {}

void printValue2() {
modify(value2);
std::cout << value2 << std::endl;
}
};

// class.cpp
void B_helper::modify(int &v) { v = v * 2 + 1; }

Overloading friend operator for template class

You declare operator<< as returning an ostream&, but there is no return statement at all in the method. Should be:

template <class T, class U>
ostream& operator<<(ostream& out, Pair<T,U>& v)
{
return out << v.val1 << " " << v.val2;
}

Other than that, I have no problems or warnings compiling your code under Visual Studio 2008 with warnings at level 4. Oh, there are the classical linker errors, but that is easily bypassed by moving the template function definition to the class declaration, as explained in the C++ FAQ.

My test code:

#include <iostream>
using namespace std;

template <class T, class U>
class Pair{
public:
Pair(T v1, U v2) : val1(v1), val2(v2){}
~Pair(){}
Pair& operator=(const Pair&);
friend ostream& operator<<(ostream& out, Pair<T,U>& v)
{
return out << v.val1 << " " << v.val2;
}
private:
T val1;
U val2;
};

int main() {
Pair<int, int> a(3, 4);
cout << a;
}

overloading operator ostream for template class in c++ not working

As the error message said, the friend declaration declares a non-template operator<<, but it's defined as a template, they don't match.

You can make the friend declaration referring to the operator template, e.g.

// forward declaration
template<class T = int, unsigned int SIZE =2>
class FixedPoint;

// declaration
template<class T,unsigned int SIZE>
std::ostream& operator<<(std::ostream& os ,const FixedPoint<T,SIZE>& price);

template<class T, unsigned int SIZE>
class FixedPoint {
public:
...
friend std::ostream& operator<< <T, SIZE> (std::ostream& os ,const FixedPoint<T, SIZE>& price);
// or just
// friend std::ostream& operator<< <> (std::ostream& os ,const FixedPoint& price);
...
};

// definition
template<class T,unsigned int SIZE>
inline std::ostream& operator<<(std::ostream& os ,const FixedPoint<T,SIZE>& price){
os << price.dollars << "." << price.cents;
return os;
}


Related Topics



Leave a reply



Submit