Declare Template Friend Function of Template Class

declare template friend function of template class

You need a few forward declarations:

template <typename T>
class Obj;

template <typename T>
Obj<T> make_obj(T t);

template <typename T>
class Obj {
private:
T & t;
Obj (T & t) : t(t) { }
Obj() = delete;

friend Obj make_obj<T>(T t);
};

template <typename T>
Obj<T> make_obj(T t) {
return Obj<T>(t);
}

live example

And BTW: I don't think you really want T & t; for your class' member variable. Probably T t; is a better choice ;)

template friend functions of template class

The simplest option is to define the friend within the class:

template<class T>
class MyVar
{
int x;

friend void printVar(const MyVar & var) {
std::cout << var.x << std::endl;
}
friend void scanVar(MyVar & var) {
std::cin >> var.x;
}
};

The downside is that the functions can only be called through argument-dependent lookup. That's not a problem in your example, but might be a problem if they don't have a suitable argument, or you want to specify the name without calling it.

If you want a separate definition, then the template will have to be declared before the class definition (so it's available for a friend declaration), but defined afterwards (so it can access the class members). The class will also have to be declared before the function. This is a bit messy, so I'll only show one of the two functions:

template <typename T> class MyVar;
template <typename T> void printVar(const MyVar<T> & var);

template<class T>
class MyVar
{
int x;

friend void printVar<T>(const MyVar<T> & var);
};

template <typename T> void printVar(const MyVar<T> & var) {
std::cout << var.x << std::endl;
}

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.

Template Friend Function of a Template Class (Friend with More Parameters)

Since there is an additional template parameter (compared to the template class parameters), it seems that one does not need to add the <> after the function name.
In conclusion, this worked fine for me:

template<std::size_t s, typename T>
class A;

template<std::size_t s, typename T, typename U>
A<s, T> operator *(U const lhs, A<s, T> const& rhs);

template<std::size_t s, typename T>
class A
{
// Blabla

template<typename U>
friend A<s, T> operator *(U const lhs, A<s, T> const& rhs);
};

template<std::size_t s, typename T, typename U>
A<s, T> operator *(U const lhs, A<s, T> const& rhs)
{
//BlaBla
}

What is the right way to define a friend function outside a template class?

Friend functions have special visibility rule (special case for ADL), so defining function outside the class is different than inside anyway.

Moreover, in case 2, the function is not template. even if you have one for every template. So to implement it outside of the class,
you would have to implement each friend double f(A<T> const& a); for every T.

The advice is the most close workaround:

  • Your function (only the specialization) is friend.
  • but your function is template (so deduction should occurs:

    with friend double f(A<T> const& a, T); (case 2), f(A<float>{}, 42); would succeed

    whereas friend double f<>(A<T> const& a, T); would not

    (T would be float for A<float> and int for 42))

  • your function is declared outside, so its visibility is "different".

Now suppose that I need to implement f in terms of a class that needs to be defined later. I such case I tried doing this:

Other work around is to declare a private method which will do the job, that allow you to have friend definition inside the class.
That private method can then be defined later:

template<class T>
class A{
double p_;

double do_f() const;
friend double f(A const& a){return a.do_f();}
};

// Thing needed by A<T>::do_f

template<class T>
double A<T>::do_f() const
{
// ...
}

If the return type is an incomplete type you have to do a trick with auto return (this works in g++11 and clang++11).

template<class T> class A;
class B;

template<class T>
class A{
B do_f() const;
friend auto f(A const& a){return a.do_f();} // not friend B f(...
};

class B{};

template<class T> B A<T>::do_f() const{return B{};}

int main(){A<double> a; f(a);}

A template friend function inside a template class

I figured out the relevant wording from the resolution of CWG 2174. It is in [temp.inst]/2 in C++17:

However, for the purpose of determining whether an instantiated redeclaration is valid according to [basic.def.odr] and [class.mem], a declaration that corresponds to a definition in the template is considered to be a definition.

Thus, the compiler is required to defer the actual instantiation of the definition until the point where a definition of foo is required to exist (in your code, there is no such point, so foo is not instantiated), but even if the definition is not instantiated, the compiler is still required to diagnose multiple definitions within the same translation unit as if the definition had been instantiated every time the declaration were instantiated.

It seems to me that this rule makes it unnecessarily difficult to use friend functions for no obvious benefit, and that it would be better if multiple definitions of a friend function defined inside a class template, instantiated within the same TU, were considered as a single definition. Perhaps, if I had more time on my hands, I would propose making such a change to the standard. (Yes, I am saying I don't have the time, so if anyone else wants to do this, please go ahead without worrying about duplicated effort.)

Unless such a change is made, it seems that you do, in fact, need to define the friend function outside the class template.

Template friend function of template class that introduces a new template parameter

It is impossible to let friend declarations refer to partial specializations - either they refer to a specific specialization or to the primary template. Moreover, function templates cannot be partially specialized anyway.

What is not possible with function templates is often doable using class templates though:

template <typename T>
struct ret_obj_helper {
// Here goes the original definition of ret_obj - the important difference
// is the location of the template parameter T, which is the one
// fixed by the friend declaration below
template <typename RetVal>
RetVal ret_obj(T t) {return RetVal(make_obj(t).t);}
};

// I guess RetVal, having to be explicitly specified, better goes first (?)
template <typename RetVal, typename T>
RetVal ret_obj(T&& t)
{
// Overcomplicated for the sake of perfect forwarding
return ret_obj_helper<typename std::remove_reference<T>::type>{}.
template ret_obj<RetVal>(std::forward<T>(t));
}

template <typename T>
class Obj {
private:
T t;
Obj (T t) : t(t) { }
Obj() = delete;

friend Obj make_obj<T>(T t);

// Make all specializations of the member function template
// of ret_obj_helper<T> a friend, regardless of the return type
template <typename RetVal>
friend RetVal ret_obj_helper<T>::ret_obj(T t);
};

Demo.

Defining a templated friend function inside a template class

The only place you declare the template function is inside the class; it is not "visible" in the enclosing namespace and hence not available for normal lookup, only for argument dependent lookup.

You need to declare (and define) it outside the class for the function to be found, and to declare it as a friend function (as you noted).

From cppreference

A name first declared in a friend declaration within class or class template X becomes a member of the innermost enclosing namespace of X, but is not accessible for lookup (except argument-dependent lookup that considers X) unless a matching declaration at the namespace scope is provided...

Template friend function of a template class

...if I change the forward declaration of operator<< so that it doesn't match

A friend function should be seen as a very special type of declaration. In essence, the compiler does enough to parse the declaration however no semantic checking will take place unless you actually specialize the class.

After making your suggested modification, if you then instantiate test you will get an error about the declarations not matching:

template class test<int>;

...However ... removing the forward declaration causes a problem

The compiler tries to parse the declaration to store it until the class template is specialized. During the parse, the compiler reaches the < in the declaration:

friend std::ostream& operator<<  <

The only way that operator<< could be followed by < is if it is a template, so a lookup takes place to check that it is a template. If a function template is found, then the < is considered to be the start of template arguments.

When you remove the forward declaration, no template is found and operator<< is considered to be an object. (This is also why when you add using namespace std the code continues to compile as there must be declarations of templates for operator<<).

...when I remove the forward declarations and use the alternative friend declaration in the code above. Note that the template parameter U doesn't appear in the following signature...

There is no requirement that all template parameters be used in the arguments of a function template. The alternative declaration is for a new function template that will only be callable if declared in the namespace and specifying explicit template arguments.

A simple example of this would be:

class A {};
template <typename T> A & operator<<(A &, int);

void foo () {
A a;
operator<< <int> (a, 10);
}

...is this code actually correct?..

Well there are two parts to this. The first is that the alternative friend function does not refer to the declaration later in the scope:

template <typename T>
class test {
template <typename U>
friend std::ostream& operator<<(std::ostream &out, const test<T> &t);
};

template <typename T>
std::ostream& operator<<(std::ostream &out, const test<T> &t); // NOT FRIEND!

The friend function would actually be declared in the namespace for each specialization:

template <typename U> 
std::ostream& operator<<(std::ostream &out, const test<int> &t);
template <typename U>
std::ostream& operator<<(std::ostream &out, const test<char> &t);
template <typename U>
std::ostream& operator<<(std::ostream &out, const test<float> &t);

Every specialization of operator<< <U> will have access to the specific specialization as per the type of its parameter test<T>. So in essence the access is restricted as you require. However as I mentioned before these functions are basically unusable as operators, since you must use function call syntax:

int main ()
{
test<int> t;
operator<< <int> (std << cout, t);
operator<< <float> (std << cout, t);
operator<< <char> (std << cout, t);
}

As per the answers to the previous question, you either use the forward declaration as suggested by litb, or you go with defining the friend function inline as per Dr_Asik's answer (which would probably be what I would do).

UPDATE: 2nd Comment

...changing the forward declaration before the class; the one in the class still matches the function that I implement later...

As I pointed out above, the compiler checks if operator<< is a template when it sees the < in the declaration:

friend std::ostream& operator<<  <

It does this by looking up the name and checking if it is a template. As long as you have a dummy forward declaration then this "tricks" the compiler into treating your friend as a template name and so the < is considered to be the start of a template argument list.

Later, when you instantiate the class, you do have a valid template to match. In essence, you're just tricking the compiler into treating the friend as a template specialization.

You can do this here because (as I said earlier), no semantic checking takes place at this point in time.



Related Topics



Leave a reply



Submit