C++ 创建一个未定义的类作为friend,并在以后定义它
结交不认识的朋友C++ 创建一个未定义的类作为friend,并在以后定义它,c++,templates,declaration,local,friend,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 tha
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;
}
模板
班级名单
{
受保护的:
甲级{
int x;
int-y;
私人:
friend class b;//代码格式不正确,Comeau拒绝该代码,并给出以下错误
error: invalid redeclaration of type name "b" (declared at
line 11)
我认为这是G++中的一个bug。英特尔C++也拒绝它。你可以通过定义类<代码> B<代码>上面的代码来修复代码。
template <typename U > class b {
int z;
U y;
};
class a {
int x;
int y;
private:
friend class b<T>;
};
模板类b{
intz;
尤伊;
};
甲级{
int x;
int-y;
私人:
b级朋友;
};
//运行此命令-它现在将为您编译
template <typename U > class b; //<----- forward declaration
template<typename T>
class List
{
protected:
class a {
int x;
int y;
private:
friend class b<T>; // <------------ Add <T>
};
template <typename U > class b {
int z;
U y;
};
public:
List() {
a* ptr = (a *)new unsigned char[sizeof(a)];
}
};
int main() {
List<int> mylist;
}
模板类b;//是您的代码无效!这是一个有趣的演示,展示了模板如何以微妙的方式改变代码的含义。以下代码是有效的:
类列表
{
公众:
甲级{
typedef int类型;
b班的朋友;//没关系!
};
模板b类;
};
b类{
List::a::键入一个_int;//允许访问私有成员
};
标准规定为7.3.1.2/3
如果非本地类中的友元声明首先声明类或函数83),则友元类或函数是最内层封闭命名空间的成员
什么时候是“第一个声明类”?上面也这么说
当查找声明为友元的类或函数的先前声明,并且友元类或函数的名称既不是限定名也不是模板id时,不考虑最内层封闭命名空间范围之外的范围
“b类”的查找从7.1.5.3/2委派到3.4.4,这反过来又委派到3.4/7的非限定名称查找。现在所有的问题是模板名称是否为“b”在友元声明类a中可见。如果不可见,则找不到名称,友元声明将引用全局范围内新声明的类。3.3.6/1关于其范围
类中声明的名称的潜在作用域不仅包括以下声明性区域
名称的声明符,以及所有函数体、默认参数和构造函数的声明符-
该类中的初始值设定项(包括嵌套类中的此类内容)
忽略一些迂腐的观点,这些观点可能会使此措辞不适用于此处(这是一个缺陷,但在该段落的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;
模板
班级名单
{
公众:
甲级{
typedef int类型;
b班的朋友;//没关系!
};
模板b类;
};
//POI
列表::a x;
当这导致隐式实例化List::a
时,将在“//POI”中查找名称a
好像有一个明确的专门化声明。在这种情况下,模板列表::b
已经声明了,这个查找将命中它并发出一个错误,因为它是一个模板类而不是非模板类。谢谢。但在您的帖子中有趣的是,在其他编译器上,这是一个重新声明错误.据我所知,重新声明不是一个错误,它不应该说不同类型的声明有冲突吗?@user420536:不一定。在MSVC++上,我得到List::b]:非类模板已经声明为类模板。
(重新声明错误)。允许不同的编译器以不同的方式解析代码,从而允许发出不同的错误消息。我没有发现该错误消息有任何错误。:)
您的分析似乎是正确的,只是在命名空间中提供匹配声明之前,通过简单的名称查找无法找到朋友的姓名作用域(在授予友谊的类声明之前或之后)。你的代码没有在COMMO、英特尔C++和MSVC++中编译。@ Prason。你引用的文本在这个例子中没有意义。朋友的名字没有在这里被查找(模板被查找)。.Compiler没有定义标准,所以我不反对编译器接受或拒绝它。GCC和Clang接受它是件好事,但我的答案并不取决于它们,而仅仅取决于我引用的标准文本。EDG前端(Intel和Comeau使用的)MSVC真的有比这更多的bug,所以这并不让我感到惊讶)。我发现文本有点难以解析。我可能错过了一些重要的东西。别介意。还要看一看和一大堆答案。无论如何,如果我的分析不正确,或者如果因为标准被打破而无法给出正确的分析,我希望被展示一个标准的文本和参数是这样显示的:)@Johannes:+1,我喜欢Comeau xD:)
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;