Friend Functions and Templates in C++

There are three common scenarios for combining friend functions and templates in C++, outlined below.

1. Class Template with Ordinary (Non-Template) Frieend Functions

1.1 Friend function does not use class template instances as parameters or return values

This behaves identically to friend functions in non-template classes. You can directly declare the ordinary function as a friend inside the class template:

#include <iostream>
template <typename DataType>
class MyContainer {
public:
    friend void printPrivateValue();

    MyContainer(DataType val);
    DataType getValue() const;
private:
    DataType storedVal;
};

template <typename DataType>
MyContainer<DataType>::MyContainer(DataType val) {
    this->storedVal = val;
}

template <typename DataType>
DataType MyContainer<DataType>::getValue() const {
    return storedVal;
}

void printPrivateValue() {
    MyContainer<int> intInstance(10);
    std::cout << intInstance.storedVal << std::endl;
}

int main() {
    printPrivateValue();
    return 0;
}

The ordinary function is granted friend access to all instantiations of the class template, so it can directly access private members of the template instance created inside the function body.

1.2 Friend funcsion uses class template instances as parameters or return values

This is similar to implementing member funcsions for a class template: the function needs a template parameter declaration, which must be included both in the friend declaration inside the class and the out-of-class definition.

#include <iostream>
template <typename DataType>
class MyContainer {
public:
    template <typename T>
    friend MyContainer<T> sumValues(MyContainer<T>& first, MyContainer<T>& second);

    MyContainer(DataType val);
    DataType getValue() const;
private:
    DataType storedVal;
};

template <typename DataType>
MyContainer<DataType>::MyContainer(DataType val) {
    this->storedVal = val;
}

template <typename DataType>
DataType MyContainer<DataType>::getValue() const {
    return storedVal;
}

template <typename T>
MyContainer<T> sumValues(MyContainer<T>& first, MyContainer<T>& second) {
    MyContainer<T> result(0);
    result.storedVal = first.storedVal + second.storedVal;
    return result;
}

int main() {
    MyContainer<int> a(10);
    MyContainer<int> b(20);
    MyContainer<int> c = sumValues(a, b);
    std::cout << c.getValue() << std::endl;
    return 0;
}

This approach lets you write a generic friend function that works with any instantiation of the class template, keeping code reusable. The compiler automatically deduces the template argument from the types of input objects during the call.


2. Non-Template Class with Function Template Friend

When a function template is declared as a friend of an ordinary non-template class, the pattern is almost identical to the previous examples: you only need to add the template parameter declaration when declaring the friend inside the class.

#include <iostream>
class DataHolder {
public:
    template <typename T>
    friend void printAnyInput(T input);

    DataHolder(int val);
    int getValue() const;
private:
    int internalVal;
};

DataHolder::DataHolder(int val) {
    this->internalVal = val;
}

int DataHolder::getValue() const {
    return internalVal;
}

template <typename T>
void printAnyInput(T input) {
    DataHolder instance(10);
    std::cout << "Input: " << input << ", Private value: " << instance.internalVal << std::endl;
}

int main() {
    printAnyInput(10);
    return 0;
}

All instantiations of the function template receive friend access to the non-template class.


3. Class Template with Function Template Friend

This most general case follows the exact same rules covered in the 1.2 scenario above, with both the class and the friend function requiring their own template parameter declarations.


Key Rules for Template Friend Functions

Overuse of friend functions is generally discouraged as it breaks encapsulation principles. When you do use them, follow these core rules:

  1. Declare the template parameter for any templated friend inside the class body:
template <typename T>
friend MyContainer<T> sumValues(MyContainer<T>& first, MyContainer<T>& second);
  1. Include the template declaration in the out-of-class implementation:
template <typename T>
MyContainer<T> sumValues(MyContainer<T>& first, MyContainer<T>& second) {
    // Implementation logic
}
  1. While template argument deduction often works for function calls, explicit template arguments are recommended for clarity:
MyContainer<int> result = sumValues<int>(first, second);

Tags: C++ Templates friend functions C++ Development

Posted on Thu, 13 Aug 2026 16:30:14 +0000 by r_a_s_robin