如何将类模板的成员模板声明为友元?编译错误修复方案
我来帮你搞定这个模板友元的坑!你想把A<T>的成员模板构造函数声明为B<T,D>的友元,但当前写法让编译器摸不着头脑,咱们一步步解决问题。
原代码
template <typename T, typename D> class B; template <typename T> class A { public: A() { } template <typename D> A(B<T, D>); }; template <typename T, typename D> class B { friend A<T>::A(B<T, D>); int x; }; template <typename T> template <typename D> A<T>::A(B<T, D> b) { b.x = 42; } int main() { B<int, double> b; A<int> a(b); return 0; }
编译错误信息
test.cc: In instantiation of ‘class B<int, double>’:
test.cc:24:18: required from here
test.cc:13:10: error: prototype for ‘A::A(B<int, double>)’ does not match any in class ‘A ’
friend A::A(B<T, D>);
^~~~
test.cc:4:7: error: candidates are: constexpr A::A(A &&)
class A {
^
test.cc:4:7: error: constexpr A::A(const A &)
test.cc:8:3: error: templateA ::A(B<T, D>) [with D = D; T = int]
A(B<T, D>);
^
test.cc:6:3: error: A::A() [with T = int]
A() { }
^
test.cc: In instantiation of ‘A::A(B<T, D>) [with D = double; T = int]’:
test.cc:25:13: required from here
test.cc:20:5: error: ‘int B<int, double>::x’ is private within this context
b.x = 42;
~~^
test.cc:14:7: note: declared private here
int x;
^
问题原因
核心问题是友元声明的语法不对:你写的friend A<T>::A(B<T, D>);是在试图声明一个非模板的成员函数为友元,但实际上A<T>的这个构造函数是个成员模板(带D模板参数),编译器找不到对应的非模板成员,自然报错;同时因为友元声明不生效,构造函数也没法访问B<T,D>的私有成员x。
修复方案
方案1:精确声明成员模板构造函数为友元
明确告诉编译器,我们要友元的是A<T>中的成员模板构造函数,需要在友元声明里加上模板参数列表:
template <typename T, typename D> class B; template <typename T> class A { public: A() { } template <typename D> A(B<T, D>); }; template <typename T, typename D> class B { // 声明A<T>中所有D2模板参数的成员构造函数为友元 template <typename D2> friend A<T>::A(B<T, D2>); int x; }; template <typename T> template <typename D> A<T>::A(B<T, D> b) { b.x = 42; } int main() { B<int, double> b; A<int> a(b); return 0; }
这种写法精准控制了友元的范围,只有A<T>的这个成员模板构造函数能访问B<T,D>的私有成员。
方案2:直接声明整个A类为友元
如果你不介意A<T>的所有成员都能访问B<T,D>的私有成员,这个写法更简单省心:
template <typename T, typename D> class B; template <typename T> class A { public: A() { } template <typename D> A(B<T, D>); }; template <typename T, typename D> class B { // 把整个A<T>类设为友元 friend class A<T>; int x; }; template <typename T> template <typename D> A<T>::A(B<T, D> b) { b.x = 42; } int main() { B<int, double> b; A<int> a(b); return 0; }
两种方案都能解决你的编译错误,选哪种取决于你对权限控制的需求~
内容的提问来源于stack exchange,提问作者bessapple14

