最Vexing的朋友?朋友化一个专门的免费函数模板会引发编译错误(当重载一个方法时)
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的数据成员。
如果出现以下情况,则不会引发编译错误:
- 我把免费函数模板的非专业化版本作为朋友(评论了代码行)
- 我从类AbstractA中删除了成员函数overloadedMethod()
问题
我无法解释langage的这种行为,所以我的问题是:
- 导致此错误的C++规则是什么?(为什么编译器会认为我在这里声明了一个数据成员?)
- 你知道背后的理由吗?(我特别想知道,如果我从类AbstractA中删除重载的Method(),它为什么会起作用。还是UB?)
首先,您的friend
声明的基本前提是健全的:
[C++11: 14.5.4/1]:
类或类模板的朋友可以是函数模板或类模板,函数模板或类别模板的专业化,也可以是普通(非模板)函数或类。对于不是模板声明的友元函数声明:
- 如果友元的名称是合格或不合格的模板id,则友元声明指的是函数模板的专用化,否则
- 如果友元的名称是限定id,并且在指定的类或命名空间中找到匹配的非模板函数,则友元声明引用该函数,否则
- 如果友元的名称是一个限定id,并且在指定的类或命名空间中找到了匹配的函数模板,则友元声明指的是该函数模板的推导专用化(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
声明中,函数声明符中使用的名称,而不是声明符id中模板参数的一部分,将首先在成员函数的类的范围中查找(10.2)。如果找不到该名称,或者该名称是宣告符id中模板参数的一部分,在授予友谊的类的定义中,查找是对不合格名称的描述。
在这种情况下,"如果找不到"子句永远不会被触发。
在GCC 4.8.1中,这会导致以下诊断:
错误:字段"overloadedMethod"的类型不完整
我确信这个诊断的具体内容有点错误—通过将模板参数列表<A>
应用于它不认为是模板的东西,您基本上混淆了编译器的糟糕之处。
即使通过限定friend
声明也无法解决此问题:
friend const A ::overloadedMethod<A>(const A& lhs, const A& rhs);
以下内容确实有效:
friend auto ::overloadedMethod<A>(const A&, const A&) -> const A;
但基于上述规则,我认为这实际上是一个编译器错误。
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 有没有办法C++将给定类的功能限制为仅另一个类(不使用继承,朋友)?
- 在课堂上创建了一个朋友,给出"无输入文件"错误
- 如何将一个部分专用的模板类的朋友变成另一个部分专用的模板类?
- B/B 树的实现与使班级成为另一个班级困境的朋友有关
- 为什么COUT在朋友函数中不起作用,该功能超载了操作员&lt;&lt;这是一个iStream运算符
- 声明一个简单模板类的variadic模板类的朋友
- 内部阶级、皮条客和一个朋友阶级——不同意的编译器
- 从另一个类访问类成员,最好使用指针还是朋友
- 如果在全局命名空间中的类中引入一个朋友,则该朋友将被全局注入
- 最Vexing的朋友?朋友化一个专门的免费函数模板会引发编译错误(当重载一个方法时)
- 我们可以添加一个基于模板参数的朋友类吗
- 一个成员函数(相对于整个类)是否可以与一个函数/类成为朋友
- 如何使模板类的一个实例与同一模板的另一个实例成为朋友
- 我如何发送一个unix-exe给我的朋友,这样他就可以通过双击运行它
- 寻找一个事先申报,由朋友介绍申报
- 让一个内部类成为C++中的朋友
- 如何使用一个公共的朋友函数来交换两个类的私有值
- c++类函数的朋友到另一个类