我有一个模板类。它具有模板功能。两者都采用不同的模板参数。有一个内部类需要与该封闭类的模板函数交朋友。编译器错误比比皆是。以下玩具示例显示了我的问题。
首先,当然会编译以下内容(VS 2017):
template <typename T>
class Class1
{
public:
Class1() = default;
~Class1() = default;
template <typename U>
void Func(U& x) {};
};
class Class2
{
public:
Class2() = default;
~Class2() = default;
template <typename T>
template <typename U>
friend void Class1<T>::Func(U& x);
};
int main()
{
Class1<int> c1;
return 0;
}
现在让我们将Class2
移至Class1
,而无需进行其他更改:
template <typename T>
class Class1
{
public:
Class1() = default;
~Class1() = default;
template <typename U>
void Func(U& x){};
class Class2
{
public:
Class2() = default;
~Class2() = default;
template <typename T> //Compiler error here.
template <typename U>
friend void Class1::Func(U& x);
};
};
int main()
{
Class1<int> c1;
return 0;
}
现在我收到编译器错误:error C3856: 'Class1<T>::Func': class is not a class template
当类嵌套时,我已经尝试了各种方法来声明朋友,但是我无法对其进行编译。可能没有办法做我想做的事。
请注意,我正在尝试执行的语义(在真实代码中,而不是在这个玩具示例中)使得Func应该是成员函数。这与迭代器或运算符无关,它们通常是非成员函数。我在这里看到了一些类似的问题,但它们通常与迭代器或运算符有关,而我还没有找到一个对我有用的解决方案的问题。
更糟糕的是,考虑到我的设计,可以将Class1
的所有人声明为Class2
的朋友(这样做可以解决此问题)。 Class2
是一个很小的辅助类,它完全与Class1
耦合;它的所有特殊成员(保存了析构函数和move ctor)都是私有的或已删除,Class1::Func
是唯一实例化Class2
的东西(并通过move ctor将其返回给{{1}的用户) }。因此,尽管不希望将整个Class1
都与朋友相处,但还是会遇到一些困难。
谢谢。
答案 0 :(得分:3)
我首先尝试在 wandbox.org 上用gcc HEAD 9.0.0重现OP的问题,并得到:
Start
prog.cc:17:23: error: declaration of template parameter 'T' shadows template parameter
17 | template <typename T> //Compiler error here.
| ^~~~~~~~
prog.cc:1:11: note: template parameter 'T' declared here
1 | template <typename T>
| ^~~~~~~~
prog.cc: In function 'int main()':
prog.cc:25:17: warning: unused variable 'c1' [-Wunused-variable]
25 | Class1<int> c1;
| ^~
1
Finish
修复很简单– T
已经是模板参数,必须在嵌套的friend
声明中重命名:
template <typename T>
class Class1
{
public:
Class1() = default;
~Class1() = default;
template <typename U>
void Func(U& x){};
class Class2
{
public:
Class2() = default;
~Class2() = default;
template <typename T1> //Compiler error gone.
template <typename U>
friend void Class1<T1>::Func(U& x);
};
};
int main()
{
Class1<int> c1;
return 0;
}
再次测试 wandbox.org :
Start
prog.cc: In function 'int main()':
prog.cc:25:17: warning: unused variable 'c1' [-Wunused-variable]
25 | Class1<int> c1;
| ^~
0
Finish
如果打算像friend void Class1::Func(U& x);
那样T
依赖于相同的模板参数Class1
,则可以选择以下解决方案:
template <typename T>
class Class1
{
public:
Class1() = default;
~Class1() = default;
template <typename U>
void Func(U& x){};
class Class2
{
public:
Class2() = default;
~Class2() = default;
template <typename U>
friend void Class1::Func(U& x);
};
};
int main()
{
Class1<int> c1;
return 0;
}
再次在 wandbox.org 上进行了测试:
Start
prog.cc: In function 'int main()':
prog.cc:24:17: warning: unused variable 'c1' [-Wunused-variable]
24 | Class1<int> c1;
| ^~
0
Finish
答案 1 :(得分:2)
这似乎是MSVS编译器中的错误。 gcc和clang都接受带有 Scheff 更正的代码。可以使用#ifdef
作为临时解决方法:
#ifdef _MSC_VER
friend class Class1;
#else
template <typename U>
friend void Class1::Func(U& x);
#endif
添加。 Bug report。