问题描述
我有一个模板类.它具有模板功能.两者都采用不同的模板参数.有一个内部类需要与该封闭类的模板函数交朋友.编译器错误比比皆是.以下玩具示例显示了我的问题.
I have a template class. It has a template function. Both take different template parameters. There is an internal class that needs to make a friend of the enclosing class's template function. Compiler errors abound. The following toy example shows my issue.
首先,当然会编译以下内容(VS 2017):
First, the following of course compiles (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
且没有其他更改:
Now let's move Class2
into Class1
with no other changes:
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
Now I get a compiler error: error C3856: 'Class1<T>::Func': class is not a class template
当类嵌套时,我已经尝试了多种方法来声明朋友,但是我无法对其进行编译.可能没有办法去做我想做的事.
I've played around with various ways to declare the friend when the class is nested, but I can't get it to compile. It's possible there is no way to do what I'm trying to do.
请注意,我要执行的操作的语义(在真实代码中,而不是在这个玩具示例中)使得Func应该是成员函数.这与迭代器或运算符无关,后者通常是非成员函数.我在这里看到过一些类似的问题,但它们通常与迭代器或运算符有关,而我还没有找到一个对我有用的解决方案的问题.
Note that the semantics of what I'm trying to do (in the real code, not this toy example) are such that Func should be a member function. This isn't about iterators or operators, which are often, of course, non-member functions. I've seen some similar questions to mine here, but they're often related to iterators or operators and I've not yet found a question with a solution that will work for me.
更糟糕的是,考虑到我的设计,将所有Class1
声明为Class2
的朋友是可以的(这样做使我可以解决此问题). Class2
是一个很小的辅助类,它完全与Class1
耦合;它的所有特殊成员(保存了析构函数和move ctor)都是私有的或已删除,并且Class1::Func
是唯一实例化Class2
的东西(并通过move ctor将其返回给Class1
的用户).因此,尽管不愿意将Class1
的全部作为朋友,但还是会遇到一些困难.
Worse comes to worse, it would be okay, given my design, to declare all of Class1
a friend of Class2
(and doing so lets me work around this issue). Class2
is a tiny helper class that is completely coupled to Class1
; all of its special members, save the destructor and move ctor, are either private or deleted, and Class1::Func
is the only thing that instantiates Class2
(and returns it via move ctor to users of Class1
). So while it's not ideal to friend the entirety of Class1
, it'd do in a pinch.
谢谢.
推荐答案
我首先尝试在并得到:
I first tried to reproduce OP's issue with gcc HEAD 9.0.0 on and got:
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
声明中重命名:
The fix is simple – T
is already a template parameter and must be renamed in the nested friend
declaration:
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;
}
在再次:
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);
依赖于与Class1
相同的模板参数T
,则可以选择以下解决方案:
If it is intended that friend void Class1::Func(U& x);
depends on the same template parameter T
like Class1
this would be the alternative solution:
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;
}
在再次:
Start
prog.cc: In function 'int main()':
prog.cc:24:17: warning: unused variable 'c1' [-Wunused-variable]
24 | Class1<int> c1;
| ^~
0
Finish
这篇关于如何将模板类X的模板成员函数声明为嵌套类X :: Y的朋友的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!