[英]Most Vexing Friend ? Friend-ing a specialized free-function template raises compilation error (when overloading a method)
我将问题简化为此示例(粘贴为单个块以便于编译)
/// \brief The free-function template,
/// which is overloading a method with the same name in AbstractA below.
template <class T>
inline const T overloadedMethod(const T& lhs, const T& rhs)
{
return T(lhs.value+rhs.value);
}
/// \brief AbstractA class
class AbstractA
{
public:
AbstractA (int aVal):
value(aVal)
{}
inline const AbstractA overloadedMethod(const AbstractA &rhs) const
{
return AbstractA(value+rhs.value);
}
protected:
int value;
};
/// \brief A class, deriving from AbstractA,
/// and friending the free-function template.
class A : public AbstractA
{
friend const A overloadedMethod <A>(const A& lhs, const A& rhs);
/// This one gives me compilation error
//template<class T> friend const T overloadedMethod(const T& lhs, const T& rhs);
/// This one would be okay
public:
A (int aVal):
AbstractA(aVal)
{}
};
int main()
{
A a1(1), a2(2);
overloadedMethod(a1, a2);
return 0;
}
基本上,我试过的编译器(VS 2010和G ++ 4.7.2)给我一个错误
friend const A overloadedMethod <A>(const A& lhs, const A& rhs);
他们似乎认为我声明了一个名为overloadedMethod的数据成员。
如果出现以下情况,则不会引发编译错误
我无法解释这种语言的行为,所以我的问题是:
首先,你friend
宣言的基本前提是合理的:
[C++11: 14.5.4/1]:
类或类模板的朋友可以是函数模板或类模板,函数模板或类模板的特化,或普通(非模板)函数或类。 对于不是模板声明的友元函数声明:
- 如果朋友的名字是限定或不合格的模板ID ,则友元声明引用功能模板的特化 ,否则
- 如果friend的名称是qualified-id并且在指定的类或命名空间中找到匹配的非模板函数,则friend声明引用该函数,否则,
- 如果friend的名称是qualified-id并且在指定的类或命名空间中找到匹配的函数模板,则friend声明引用该函数模板的推导特化(14.8.2.6),否则,
- 名称应为声明(或重新声明)普通(非模板)函数的非限定id 。
[例如:
template<class T> class task; template<class T> task<T>* preempt(task<T>*); template<class T> class task { friend void next_time(); friend void process(task<T>*); friend task<T>* preempt<T>(task<T>*); template<class C> friend int func(C); friend class task<int>; template<class P> friend class frd; };
[..] - 最后的例子]
您可能遇到问题,因为基类中的名称overloadedMethod
隐藏了全局问题 - 无论参数列表如何不同,以及基本名称不代表模板这一事实:
[C++11: 3.4.1/9]:
在授予友谊的类中内联定义的友元函数(11.3)定义中使用的名称的名称查找应按照成员函数定义中的查找进行。 如果在授予友谊的类中未定义友元函数,则友元函数定义中的名称查找应如命名空间成员函数定义中的查找所述进行。
[C++11: 3.4.1/10]:
在命名成员函数的friend
声明中,首先在范围内查找函数声明符中使用的名称而不是declarator-id中的template-argument的一部分。成员函数的类 (10.2)。 如果找不到,或者名称是declarator-id中 template-argument的一部分,则查找与授予友谊的类定义中的非限定名称一样。
在这种情况下,永远不会触发“if not found”子句。
在GCC 4.8.1中, 这导致以下诊断 :
错误:字段'overloadedMethod'具有不完整的类型
我确信这个诊断的具体内容有点错误 - 通过将template-parameter-list <A>
应用于它认为不是模板的东西,你基本上混淆了你的编译器。
即使通过限定friend
声明 ,你也无法解决这个问题:
friend const A ::overloadedMethod<A>(const A& lhs, const A& rhs);
以下工作:
friend auto ::overloadedMethod<A>(const A&, const A&) -> const A;
但我认为这实际上是一个基于上述规则的编译器错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.