问题
If I have a normal class I can "inject" a non-free friend function inside the class. (That among other things can be only be found by ADL).
case 1:
class A{
double p_;
friend double f(A const& a){return a.p_;}
};
If instead this is a template class I can do:
case 2:
template<class T>
class A{
double p_;
friend double f(A const& a){return a.p_;} // apparently A const& is a synomyn for A<T> const&
};
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:
case 3:
template<class T>
class A{
double p_;
friend double f(A const& a);
};
...
This already gives a warning: "warning: friend declaration ‘double f(const A&)’ declares a non-template function [-Wnon-template-friend]".
Following the advice from the compiler I can do this:
template<class T> class A;
template<class T> double f(A<T> const& a);
template<class T>
class A{
double p_;
friend double f<>(A const& a);
};
template<class T> double f(A<T> const& a){return a.p_;}
Which requires so much more code and I am not even sure it is 100% equivalent to case 2 abov which is what I want, because now I have a truly free function that happens to be a friend instead of an injected friend.
Can case 3 be modified to be 100% equivalent to case 2 and still have a definition of f
outside the class? In other words can one inject a friend function that is defined out of the class?
I tried this also, which gives a compiler error:
template<class T>
class A{
double p_;
friend double f(A<T> const& a);
};
template<class T> double A<T>::f(A<T> const& a){return a.p_;}
This answer finds the same solution but doesn't answer the question about case 3 being equivalent to case 2. What is the right way to write friend function declarations in template class?
回答1:
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:
withfriend double f(A<T> const& a, T);
(case 2),f(A<float>{}, 42);
would succeed
whereasfriend double f<>(A<T> const& a, T);
would not
(T
would befloat
forA<float>
andint
for42
))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);}
来源:https://stackoverflow.com/questions/52749225/what-is-the-right-way-to-define-a-friend-function-outside-a-template-class