将未定义的类设为友元,然后再定义它

发布于 2024-10-04 21:18:45 字数 626 浏览 3 评论 0原文

交一个不认识的朋友

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;
}

请浏览此链接,我在代码中以评论形式提出了我的问题。 我正在努力让另一个班级成为我班级的朋友。但在交朋友时并不知道那个班级。允许它的 C++ 规则是什么。 后来我以这样的方式定义该类,它与朋友声明不兼容。为什么不抛出错误。 谢谢

Making an unknown 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;
}

Please go through this link, I have my questions as comments in the code.
I am trying to make another class a friend of my class. But that class is not know at the time of making friend. What is the C++ rule that allows for it.
Later I am defining that class in such a way that, it is incompatible with the friend declaration. Why is that not throwing an error.
Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦与时光遇 2024-10-11 21:18:45

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

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
};

标准为 7.3.1.2/3

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

什么时候是“首次宣布的班级”?那里也这么说

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

“class b”的查找从 7.1.5.3/2 委托给 3.4.4,3.4.4 又委托给 3.4/7 处的非限定名称查找。现在的所有问题是模板名称“b”在友元声明类 a 中是否可见。如果不是,则找不到该名称,并且友元声明将引用全局范围内新声明的类。 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; 

当导致 List::a 被隐式实例化时,名称 a 会在“// POI”中查找,就好像将会有一个明确的专业化声明。在这种情况下,模板 List::b 已经被声明,并且此查找将命中它并发出错误,因为它是模板而不是非模板类。

Yes your code is invalid! This is an interesting show of how templates can change meaning of code in subtle ways. The following code is valid:

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
};

Standard says at 7.3.1.2/3

If a friend declaration in a non-local class first declares a class or function83) the friend class or function is a member of the innermost enclosing namespace.

When is it a "first declared class"? It says that too there

When looking for a prior declaration of a class or a function declared as a friend, and when the name of the friend class or function is neither a qualified name nor a template-id, scopes outside the innermost enclosing namespace scope are not considered.

The lookup for "class b" is delegated from 7.1.5.3/2 to 3.4.4 which in turn delegates to unqualified name lookup at 3.4/7. All the question now is whether the template-name "b" is visible in the friend declaration class a. If it isn't, the name is not found and the friend declaration will refer to a new declared class at global scope. 3.3.6/1 about the scope of it says

The potential scope of a name declared in a class consists not only of the declarative region following
the name’s declarator, but also of all function bodies, default arguments, and constructor ctor-
initializers in that class (including such things in nested classes).

Ignoring a few pedantic points that would make this wording not apply to here (which were a defect but are fixed in the C++0x version of that paragraph which also makes this easier to read), this list does not include the friend declaration as an area where that template name is visible.

However, the friend was declared in a member class of a class template. When the member class is instantiated different lookup applies - the lookup for friend names declared in a class template! The Standard says

Friend classes or functions can be declared within a class template. When a template is instantiated, the
names of its friends are treated as if the specialization had been explicitly declared at its point of instantiation.

So the following code is invalid:

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; 

When that causes List<int>::a to be implicitly instantiated, the name a is looked up at "// POI" as if there would have been an explicit specialization declared. In that case, the template List::b has already been declared, and this lookup will hit it and emit an error because it's a template and not a non-template class.

暮年 2024-10-11 21:18:45

//运行它-它现在将为您编译

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;

}

//Run this- it now will compile for you

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;

}
浪推晚风 2024-10-11 21:18:45

该代码格式不正确,Comeau 拒绝它并给出以下错误,

error: invalid redeclaration of type name "b" (declared at
      line 11)

我认为这是 g++ 中的一个错误。 Intel C++ 也拒绝它。您可以通过在 A 上方定义类 B 来修复代码。

template <typename U > class b { 
        int z;
        U y;
};
class a {
        int x;
        int y;
    private:
        friend class b<T>;  
};

The code is ill-formed and Comeau rejects it giving the following error

error: invalid redeclaration of type name "b" (declared at
      line 11)

I think this is a bug in g++. Intel C++ rejects it too. You can fix the code by defining class B above A.

template <typename U > class b { 
        int z;
        U y;
};
class a {
        int x;
        int y;
    private:
        friend class b<T>;  
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文