C++ 最烦人的朋友?重载专用自由函数模板会引发编译错误(重载方法时) 代码

C++ 最烦人的朋友?重载专用自由函数模板会引发编译错误(重载方法时) 代码,c++,templates,friend,C++,Templates,Friend,我将问题简化为这个示例(粘贴为单个块以便于编译) //\简要介绍自由函数模板, ///这是在下面的AbstractA中重载具有相同名称的方法。 模板 内联常量T重载方法(常量T和lhs、常量T和rhs) { 返回T(左侧值+右侧值); } ///\brief抽象类 抽象类 { 公众: 摘要(int aVal): 价值(aVal) {} inline const AbstractA重载方法(const AbstractA&rhs)const { 返回AbstractA(value+rhs.valu

我将问题简化为这个示例(粘贴为单个块以便于编译)

//\简要介绍自由函数模板,
///这是在下面的AbstractA中重载具有相同名称的方法。
模板
内联常量T重载方法(常量T和lhs、常量T和rhs)
{
返回T(左侧值+右侧值);
}
///\brief抽象类
抽象类
{
公众:
摘要(int aVal):
价值(aVal)
{}
inline const AbstractA重载方法(const AbstractA&rhs)const
{
返回AbstractA(value+rhs.value);
}
受保护的:
int值;
};
///\简述一个类,源自AbstractA,
///和友好的自由功能模板。
A类:公共文摘A
{   
友元常量A重载方法(常量A和lhs、常量A和rhs);
///这个给了我编译错误
//模板友元常量T重载方法(常量T&lhs、常量T&rhs);
///这个可以
公众:
A(国际货币):
摘要(aVal)
{}
};
int main()
{
A a1(1)、a2(2);
超载法(a1,a2);
返回0;
}
细节 基本上,我试过的编译器(VS2010和G++4.7.2)给了我一个错误

friend const A overloadedMethod <A>(const A& lhs, const A& rhs);
friend const A重载方法(const A&lhs,const A&rhs);
他们似乎认为我正在声明一个名为overloadedMethod的数据成员

如果出现以下情况,则不会引发编译错误:

  • 我将免费函数模板的非专用版本作为朋友(注释代码行)
  • 我从类AbstractA中删除成员函数overloadedMethod()
问题 我无法解释langage的这种行为,所以我的问题是:

    什么是导致这个错误的C++规则?(为什么编译器会认为我在这里声明了数据成员?)
  • 你知道背后的理由吗?(我特别想知道,如果我从类AbstractA中删除重载方法(),它为什么会起作用。或者它是UB?)

首先,你的朋友声明的基本前提是合理的:

[C++11:14.5.4/1]:
类或类模板的朋友可以是函数模板或类模板、函数模板或类模板的特殊化,或普通(非模板)函数或类。对于不是模板声明的友元函数声明:

  • 如果友元的名称是合格或不合格的模板id,则友元声明引用函数模板的专门化,否则
  • 如果友元的名称是限定id,并且在指定的类或命名空间中找到匹配的非模板函数,则友元声明引用该函数,否则
  • 如果友元的名称是限定id,并且在指定的类或命名空间中找到匹配的函数模板,则友元声明引用该函数模板(14.8.2.6)的推断专门化,否则
  • 名称应为声明(或重新声明)普通(非模板)函数的非限定id
[示例:

以下方法确实有效:

friend auto ::overloadedMethod<A>(const A&, const A&) -> const A;
friend auto::重载方法(const A&,const A&)->const A;

但根据上述规则,我认为这实际上是一个编译器错误。

我怀疑您能否将非成员函数模板专门化为
朋友
“成员”.@Tony:什么能阻止这种情况发生?不管怎样,正如问题中所述,编译器对这个特殊的非成员friend函数模板很满意,只要它的名称与父类中的方法不同。@Tony:C++11:11.3/3]
中的非规范性文本说“朋友声明可以是模板声明中的声明(第14、14.5.4条)。“据我所知,14.5.4/1甚至明确允许此程序。我相信如果您将名称设置为限定id,此问题将得到解决。基本名称隐藏了全局名称,没有?@catscradel我们这里没有定义,只有一个声明。但这是可行的:
friend auto::overloadedMethod(const a&,const a&)->const a;
(之前有一个打字错误)@DyP:更新了我认为相关的标准段落。你为什么认为这是一个编译器错误?(你是如何使用引用的规则得出这个结论的?)@DyP规则说,查找不应该找到模板,但是你的代码可以编译。老实说,我已经达到了某种程度,在这里——整个事情似乎没有指定。
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;
};
friend const A ::overloadedMethod<A>(const A& lhs, const A& rhs);
friend auto ::overloadedMethod<A>(const A&, const A&) -> const A;