我将问题简化为此示例(粘贴为单个块以便于编译)
/// \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 的数据成员。
如果出现以下情况,则不会引发编译错误:
我无法解释这种语言的行为,所以我的问题是:
答案 0 :(得分:4)
首先,friend
声明的基本前提是合理的:
[C++11: 14.5.4/1]:
类或类模板的朋友可以是函数模板或类模板,函数模板或类模板的特化,或普通(非模板)函数或类。对于不是模板声明的友元函数声明:
- 如果朋友的姓名是合格或不合格的 template-id ,则朋友声明会引用功能模板的专业化,否则
- 如果朋友的名字是 qualified-id 并且在指定的类或命名空间中找到匹配的非模板函数,则friend声明引用该函数,否则,
- 如果朋友的名称是 qualified-id 并且在指定的类或命名空间中找到匹配的函数模板,则friend声明引用该函数模板的推导的特化(14.8。 2.6),否则,
- 该名称应为 unqualified-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
声明中,函数声明符中使用的名称,而不是 template-argument 的一部分> declarator-id 首先在成员函数的类(10.2)的范围内查找。如果找不到,或者名称是 declarator-id 中 template-argument 的一部分,则查找的内容与定义中的非限定名称相同。授予友谊的阶级。
在这种情况下永远不会触发“如果找不到”子句。
在GCC 4.8.1中this results in the following diagnostic:
错误:字段'overloadedMethod'的类型不完整
我确信这个诊断的具体内容有点错误 - 你基本上混淆了你的编译器,通过应用 template-parameter-list <A>
对于它不相信的东西是一个模板。
您无法解决此问题,even by qualifying the friend
declaration:
friend const A ::overloadedMethod<A>(const A& lhs, const A& rhs);
以下工作正常:
friend auto ::overloadedMethod<A>(const A&, const A&) -> const A;
但我认为这实际上是一个基于上述规则的编译器错误。