将未定义的类作为朋友,并在以后定义它

Sau*_*abh 7 c++ templates declaration local friend

做一个不知名的朋友

template<typename T>
class List
{
protected:

    class a {
        int x;
        int y;
    private:
        friend class b;  // <------------ Why this is not an error? 
    };

    template <typename U > class b {  //If that is not a error this should be an error
        int z;
        U y;
    };

    public:
        List() {
            a* ptr = (a *)new unsigned char[sizeof(a)];
        }
};

int main() {
    List<int>  mylist;
}
Run Code Online (Sandbox Code Playgroud)

请仔细阅读此链接,我在代码中提出了我的问题.我想让另一堂课成为我班上的朋友.但在结交朋友的时候,那个班级并不知道.什么是允许它的C++规则.后来我以这样的方式定义该类,它与朋友声明不兼容.为什么不抛出错误.谢谢

Joh*_*itb 6

是的,你的代码无效!这是一个有趣的展示模板如何以微妙的方式改变代码的含义.下面的代码有效的:

class List
{
public:
    class a {
        typedef int type;
        friend class b; // that's fine!
    };

    template <typename U > class b;
};

class b {
  List::a::type an_int; // allowed to access private member
};
Run Code Online (Sandbox Code Playgroud)

标准说明在7.3.1.2/3

如果非本地类中的友元声明首先声明一个类或函数,则该友元类或函数是最内层封闭命名空间的成员.

什么时候是"第一次宣布的课程"?它也说那里

当查找声明为朋友的类或函数的先前声明时,并且当友元类或函数的名称既不是限定名称也不是模板标识时,不考虑最内部封闭命名空间范围之外的范围.

"class b"的查找从7.1.5.3/2委派给3.4.4,后者又委托3.4/7处的非限定名称查找.现在的所有问题是模板名称"b"是否在朋友声明类a中可见.如果不是,则找不到名称,并且friend声明将引用全局范围内的新声明的类.3.3.6/1关于它的范围说

在类中声明的名称的潜在范围不仅包括名称声明符后面的声明性区域,还包括该类中所有函数体,默认参数和构造函数ctor-初始化器(包括嵌套类中的这些内容).

忽略一些会使这个措辞不适用于此处的迂腐点(这是一个缺陷但在该段的C++ 0x版本中修复,这也使这更容易阅读),此列表不包括朋友声明为该模板名称可见的区域.

但是,该朋友是在类模板的成员类中声明的.实例化成员类时,将应用不同的查找 - 查找在类模板中声明的朋友名称!标准说

可以在类模板中声明好友类或函数.实例化模板时,会将其朋友的名称视为在实例化时明确声明了特化.

所以以下代码无效:

template<typename T>
class List
{
public:
    class a {
        typedef int type;
        friend class b; // that's fine!
    };

    template <typename U > class b;
};

// POI
List<int>::a x; 
Run Code Online (Sandbox Code Playgroud)

当这导致List<int>::a隐式实例化时,名称将a被查找为"// POI",就好像已经声明了显式特化.在这种情况下,模板List::b已经被声明,并且此查找将命中它并发出错误,因为它是模板而不是非模板类.