在模板类中定义的朋友功能

时间:2019-01-29 08:13:19

标签: c++ c++11

在模板类A中定义了一个名为test()的朋友函数:

template <typename T> class A {
public:
    friend void cs() {/* code */}
}

另一个类继承自模板类A:

class B : public A<B> {}

在主函数中,我无法调用cs(),如果我没有在全局范围内提供函数声明,则编译器将看不到其声明:

int main(){
    cs()
}

但是当cs以其模板类T作为参数时,情况就不同了:

template <typename T> class A{
public:
    friend void cs(const T& t) {}
}

现在可以在主函数中成功调用cs()而不进行任何缩放:

int main(){
    B b;
    cs(b);
}

如果函数将用户定义的类作为其参数,我知道编译器将搜索用户定义的类的范围。那么,cs()到底定义了哪个范围?在第二种情况下如何成功调用cs()?

3 个答案:

答案 0 :(得分:6)

  

如果函数将用户定义的类作为其参数,我知道编译器将搜索用户定义的类的范围。

是的,它称为ADL。当您编写cs(b)时,编译器将搜索名为cs的函数。它找不到任何东西,这就是您的第一个示例中发生的情况。

但是现在,由于cs采用b,因此编译器还可以在b的范围内搜索名为cs的函数。在第一个示例中这是不可能的,因为没有参数!在B中找到void cs(const B&),然后使用它。

  

那么cs()到底定义了哪个范围?

在全局范围内,但是如果没有ADL,则cs对于命名查找是不可见的。

  

在第二种情况下如何成功调用cs()?

如前所述,可以通过cs上的ADL找到B

答案 1 :(得分:2)

请注意,friend declaration引入的名称cs对普通名称查找不可见;这就是为什么第一种情况失败的原因,除非您在名称空间范围内提供声明。

  

首先在类或类模板X的朋友声明中声明的名称成为X的最内层封闭名称空间的成员,但对于查找(除非考虑X的依赖于参数的查找除外)不可见,除非在提供了命名空间范围

在第二种情况下,由于ADL成功找到了名称cs;您可以为cs指定一个参数。

  

依赖于参数的查找(也称为ADL或Koenig查找)是用于在函数调用表达式中查找不合格函数名称的规则集,包括对重载运算符的隐式函数调用。除了通常的非限定名称查找所考虑的范围和名称空间之外,还在其参数的名称空间中查找这些函数名称。

  

那么cs()到底定义了哪个范围?

名称cs成为A最内层的命名空间(即此处的全局命名空间)的成员,但对于普通名称查找来说是不可见的。

答案 2 :(得分:1)

  

如果函数将用户定义的类作为其参数,我知道编译器将搜索用户定义的类的范围。那么,cs()到底定义了哪个范围?在第二种情况下如何成功调用cs()?

您在这里描述依赖于参数的查找。正是这样找到cs

cs与定义A<B>的名称空间相同,即A的名称空间和范围。

出于ADL的目的,实现收集“关联的名称空间”。这些也包括基类的名称空间。

  

[basic.lookup.argdep]

     

2.2如果T是一个类类型(包括并集),则其关联   类是:类本身;它所属的类,如果   任何;及其直接和间接基类。其相关   名称空间是其关联的最内层的封闭名称空间   类。此外,如果T是一个类模板专门化,则其   关联的名称空间和类还包括:名称空间和   与提供的模板参数类型相关的类   用于模板类型参数(不包括模板模板参数);   任何模板模板参数为其成员的名称空间;   以及将任何成员模板用作模板的类   模板参数是成员。 [注意:非类型模板参数   对关联的命名空间不起作用。 —尾注]