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

这一生的挚爱 提交于 2020-02-05 13:11:12

问题


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:
    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);}


来源:https://stackoverflow.com/questions/52749225/what-is-the-right-way-to-define-a-friend-function-outside-a-template-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!