在模板外定义友元函数的正确方法是什么 class?
What is the right way to define a friend function outside a template class?
如果我有一个正常的 class 我可以 "inject" 在 class 里面添加一个非自由的好友函数。 (除其他外,只能通过 ADL 找到)。
案例 1:
class A{
double p_;
friend double f(A const& a){return a.p_;}
};
如果这是一个模板 class 我可以这样做:
案例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&
};
现在假设我需要根据需要稍后定义的 class 来实现 f
。在这种情况下,我尝试这样做:
案例 3:
template<class T>
class A{
double p_;
friend double f(A const& a);
};
...
这已经给出了警告:"warning: friend declaration ‘double f(const A&)’ declares a non-template function [-Wnon-template-friend]"。
根据编译器的建议,我可以这样做:
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_;}
这需要更多的代码,我什至不确定它是否 100% 等同于上面的情况 2,这正是我想要的,因为现在我有一个真正自由的函数,它恰好是一个朋友而不是一个注入朋友。
是否可以将案例 3 修改为 100% 等同于案例 2,并且在 class 之外仍然有 f
的定义?换句话说,可以注入一个由 class?
定义的友元函数吗?
我也试过这个,它给出了一个编译器错误:
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_;}
这个答案找到了相同的解决方案,但没有回答案例 3 等同于案例 2 的问题。
友元函数具有特殊的可见性规则(ADL 的特殊情况),因此在 class 外部定义函数与在内部定义函数无论如何是不同的。
此外,在情况2中,函数不是模板。即使每个模板都有一个。所以要在 class 之外实现它,
您必须为每个 T
.
实现每个 friend double f(A<T> const& a);
建议是最接近的解决方法:
- 你的功能(只有专业化)是朋友。
但是你的函数是模板(所以推导应该发生:
使用 friend double f(A<T> const& a, T);
(案例 2),f(A<float>{}, 42);
会成功
而 friend double f<>(A<T> const& a, T);
不会
(T
对于 A<float>
将是 float
,对于 42
将是 int
))
你的函数是在外面声明的,所以它的可见性是"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:
其他解决方法是声明一个私有方法来完成这项工作,允许您在 class 中定义好友。
然后可以稍后定义该私有方法:
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
{
// ...
}
如果 return 类型是一个不完整的类型,你必须用 auto
return 做一个技巧(这在 g++11 和 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);}
如果我有一个正常的 class 我可以 "inject" 在 class 里面添加一个非自由的好友函数。 (除其他外,只能通过 ADL 找到)。
案例 1:
class A{
double p_;
friend double f(A const& a){return a.p_;}
};
如果这是一个模板 class 我可以这样做:
案例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&
};
现在假设我需要根据需要稍后定义的 class 来实现 f
。在这种情况下,我尝试这样做:
案例 3:
template<class T>
class A{
double p_;
friend double f(A const& a);
};
...
这已经给出了警告:"warning: friend declaration ‘double f(const A&)’ declares a non-template function [-Wnon-template-friend]"。
根据编译器的建议,我可以这样做:
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_;}
这需要更多的代码,我什至不确定它是否 100% 等同于上面的情况 2,这正是我想要的,因为现在我有一个真正自由的函数,它恰好是一个朋友而不是一个注入朋友。
是否可以将案例 3 修改为 100% 等同于案例 2,并且在 class 之外仍然有 f
的定义?换句话说,可以注入一个由 class?
我也试过这个,它给出了一个编译器错误:
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_;}
这个答案找到了相同的解决方案,但没有回答案例 3 等同于案例 2 的问题。
友元函数具有特殊的可见性规则(ADL 的特殊情况),因此在 class 外部定义函数与在内部定义函数无论如何是不同的。
此外,在情况2中,函数不是模板。即使每个模板都有一个。所以要在 class 之外实现它,
您必须为每个 T
.
friend double f(A<T> const& a);
建议是最接近的解决方法:
- 你的功能(只有专业化)是朋友。
但是你的函数是模板(所以推导应该发生:
使用friend double f(A<T> const& a, T);
(案例 2),f(A<float>{}, 42);
会成功
而friend double f<>(A<T> const& a, T);
不会
(T
对于A<float>
将是float
,对于42
将是int
))你的函数是在外面声明的,所以它的可见性是"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:
其他解决方法是声明一个私有方法来完成这项工作,允许您在 class 中定义好友。 然后可以稍后定义该私有方法:
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
{
// ...
}
如果 return 类型是一个不完整的类型,你必须用 auto
return 做一个技巧(这在 g++11 和 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);}