在 C++ 中,为什么不能使用另一个 class 的模板类型将模板 class 成员函数加好友?
In C++, why isn't it possible to friend a template class member function using the template type of another class?
换句话说,为什么编译正常:
template<typename Type>
class A{
public:
void f();
};
class B{
friend void A<int>::f();
};
template<>
void A<int>::f(){
B* var = new B();
}
虽然这不是 :
template<typename Type>
class A{
public:
void f();
};
template<typename Type> // B is now a templated class
class B{
friend void A<Type>::f(); // Friending is done using B templated type
};
template<>
void A<int>::f(){
B<int>* var = new B<int>(); // var is now declared using int as its templated type
}
对于第二个代码片段,编译器(gcc 6.2,无特殊标志)表示:
main.cpp: In instantiation of ‘class B<int>’:
main.cpp:14:28: required from here
main.cpp:9:15: error: prototype for ‘void A<int>::f()’ does not match any in class ‘A<int>’
friend void A<Type>::f();
^~~~~~~
main.cpp:13:6: error: candidate is: void A<Type>::f() [with Type = int]
void A<int>::f(){
据我了解,在第二个代码片段中,当声明 var 时,编译器应该解析 B class 声明,将 friend 声明中使用的类型替换为 int,一切正常。我错过了什么?
编辑:下面的评论指出第二个代码片段似乎可以使用 clang 和 Visual C++ 2015 正确编译
特化 template class
成员函数而不特化整个 template class
是允许特化非 template
成员函数的特殊情况,所以 GCC
可能会感到困惑,我不知道原因,但不知何故你不能向 template class
的非 template
专门成员宣布友谊。临时解决方案是专门化整个 class template
以使其工作。
//class template A
template<typename Type>
class A{
public:
void f();
};
//class A<int>
template<>
class A<int>{
public:
void f();
};
然后,定义A<int>::f
:
对于class B:
void A<int>::f(){
B* var = new B();
(void)(var);
}
对于template class B
:
void A<int>::f(){
B<int>* var = new B<int>();
(void)(var);
}
不过我觉得Clang
就在这里,这样的好友声明应该没有问题。这可能是 GCC
.
中的错误
B<int>
在 A<int>::f()
中使用之前的显式实例化解决了这个问题。我假设 GCC 尝试在 A<int>::f()
的定义中隐式实例化 B<int>
。但是 A<int>::f()
的定义还没有完成,GCC 'looses' 的友元声明。看起来像是编译器问题。
template<typename Type>
class A
{
public:
void f();
};
template<typename Type> // B is now a templated class
class B
{
friend void A<Type>::f(); // Friending is done using B templated type
};
template
class B<int>; // <= explicit instantiation, that works
template<>
void A<int>::f()
{
B<int>* var = new B<int>();
}
换句话说,为什么编译正常:
template<typename Type>
class A{
public:
void f();
};
class B{
friend void A<int>::f();
};
template<>
void A<int>::f(){
B* var = new B();
}
虽然这不是 :
template<typename Type>
class A{
public:
void f();
};
template<typename Type> // B is now a templated class
class B{
friend void A<Type>::f(); // Friending is done using B templated type
};
template<>
void A<int>::f(){
B<int>* var = new B<int>(); // var is now declared using int as its templated type
}
对于第二个代码片段,编译器(gcc 6.2,无特殊标志)表示:
main.cpp: In instantiation of ‘class B<int>’:
main.cpp:14:28: required from here
main.cpp:9:15: error: prototype for ‘void A<int>::f()’ does not match any in class ‘A<int>’
friend void A<Type>::f();
^~~~~~~
main.cpp:13:6: error: candidate is: void A<Type>::f() [with Type = int]
void A<int>::f(){
据我了解,在第二个代码片段中,当声明 var 时,编译器应该解析 B class 声明,将 friend 声明中使用的类型替换为 int,一切正常。我错过了什么?
编辑:下面的评论指出第二个代码片段似乎可以使用 clang 和 Visual C++ 2015 正确编译
特化 template class
成员函数而不特化整个 template class
是允许特化非 template
成员函数的特殊情况,所以 GCC
可能会感到困惑,我不知道原因,但不知何故你不能向 template class
的非 template
专门成员宣布友谊。临时解决方案是专门化整个 class template
以使其工作。
//class template A
template<typename Type>
class A{
public:
void f();
};
//class A<int>
template<>
class A<int>{
public:
void f();
};
然后,定义A<int>::f
:
对于class B:
void A<int>::f(){
B* var = new B();
(void)(var);
}
对于template class B
:
void A<int>::f(){
B<int>* var = new B<int>();
(void)(var);
}
不过我觉得Clang
就在这里,这样的好友声明应该没有问题。这可能是 GCC
.
B<int>
在 A<int>::f()
中使用之前的显式实例化解决了这个问题。我假设 GCC 尝试在 A<int>::f()
的定义中隐式实例化 B<int>
。但是 A<int>::f()
的定义还没有完成,GCC 'looses' 的友元声明。看起来像是编译器问题。
template<typename Type>
class A
{
public:
void f();
};
template<typename Type> // B is now a templated class
class B
{
friend void A<Type>::f(); // Friending is done using B templated type
};
template
class B<int>; // <= explicit instantiation, that works
template<>
void A<int>::f()
{
B<int>* var = new B<int>();
}