ADL 和友元注入

发布于 2024-09-17 12:41:21 字数 843 浏览 1 评论 0原文

考虑一下这段代码:

template <int N>
struct X
{
 friend void f(X *) {}
};

int main()
{
 f((X<0> *)0); // Error?
}

编译器似乎非常不同意。 (MSVC08/10 说不,GCC<4.5 说是,但 4.5 说不,sun 5.1 说是,intel 11.1 也说是,但 comeau 说不(都是 EDG))。

根据《C++ 模板 - 完整指南》:

...假设有一个调用 涉及查找好友 关联的类实际上会导致 要实例化的类...虽然 这显然是那些人的意图 编写了 C++ 标准,但它不是 标准中明确规定。

我在标准中找不到相关部分。有什么参考吗?

考虑这种变化:

template <int N>
struct X
{
 template <int M>
 friend void f(X<M> *) {}
};

template <>
struct X<0>
{
};

int main()
{
 X<1>();
 f((X<0> *)0); // Error?
}

这里的关键问题是 X<1> 注入的可行函数在 X<0> 的 ADL 期间是否应该可见?他们有关联吗?上面提到的所有编译器都接受此代码,但 Comeau 除外,它仅在宽松模式下接受它。也不确定标准对此有何规定。

你对此有何看法?

Consider this code:

template <int N>
struct X
{
 friend void f(X *) {}
};

int main()
{
 f((X<0> *)0); // Error?
}

compilers seem to heavily disagree. (MSVC08/10 says no, GCC<4.5 says yes, but 4.5 says no, sun 5.1 says yes, intel 11.1 says yes too but comeau says no (both are EDG)).

According to "C++ Templates - The complete guide":

... it is assumed that a call
involving a lookup for friends in
associated classes actually causes the
class to be instantiated ... Although
this was clearly intended by those who
wrote the C++ standard, it is not
clearly spelled out in the standard.

I couldn't find the relevant section in the standard. Any reference?

Consider this variation:

template <int N>
struct X
{
 template <int M>
 friend void f(X<M> *) {}
};

template <>
struct X<0>
{
};

int main()
{
 X<1>();
 f((X<0> *)0); // Error?
}

The key issue here is wether the viable function injected by X<1> should be visible during ADL for X<0>? Are they associated? All compilers mentioned above accept this code, except for Comeau which only accepts it in relaxed mode. Not sure what the standard has to say about this either.

What's your take on that?

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

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

发布评论

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

评论(1

夕色琉璃 2024-09-24 12:41:21

标准在 14.7.1/4 中表示

如果类类型在需要完全定义的对象类型的上下文中使用,或者类类型的完整性影响程序的语义,则类模板特化会被隐式实例化;特别是,如果类型为类模板特化的表达式涉及重载解析、指针转换、指向成员的指针转换,则隐式实例化类模板特化(3.2);

请注意,Vandervoorde 在此处发布了问题报告 ,委员会发现

标准已经指定这会创建一个实例化点。

对于第二种情况 - 您需要考虑参数 f(X<0>*) 的关联类和命名空间。这些是,因为这是一个指向类模板专门化的指针(请注意,下面的“template-id”不太正确 - C++0x 更正了它以使用正确的术语),也是一个指向类的指针(这种令人困惑的分割在 C++0x 中也得到了纠正 - 它在一个要点中列出了这两种情况)。

  • 如果 T 是模板 ID,则其关联的命名空间和类是模板所在的命名空间
    定义; [...很多噪音...]

  • 如果 T 是类类型(包括联合),则其关联类为: 类本身;它所属的类别(如果有);及其直接和间接基类。其关联的命名空间是定义其关联的类的命名空间。

总而言之,我们的关联类是 X<0> ,关联的命名空间是全局命名空间。现在可见的友元函数是

  • 在关联类中声明的任何命名空间范围的友元函数在其各自的命名空间内都是可见的,即使它们在普通查找期间不可见

X<0> 中没有声明友元函数,因此友元函数声明为查看全局命名空间时不可见。请注意,X<0> 是与 X<1> 完全不同的类类型。您在那里执行的 X<1> 隐式实例化对此调用没有任何影响 - 它只是将一个不可见的名称添加到引用类 X<1> 的友元函数的全局命名空间中。 1>

The Standard says at 14.7.1/4

A class template specialization is implicitly instantiated if the class type is used in a context that requires a completely-defined object type or if the completeness of the class type affects the semantics of the program; in particular, if an expression whose type is a class template specialization is involved in overload resolution, pointer conversion, pointer to member conversion, the class template specialization is implicitly instantiated (3.2);

Note that Vandervoorde made an issue report here, and the committee found

The standard already specifies that this creates a point of instantiation.

For your second case - you need to consider the associated classes and namespaces of the argument f(X<0>*). These are, since this is a pointer to a class template specialization (note that "template-id" below is not quite correct - C++0x corrected that to use the correct term) and also a pointer to a class (this confusing split was also corrected in C++0x - it lists these two cases in one bullet point).

  • If T is a template-id, its associated namespaces and classes are the namespace in which the template is
    defined; [... lots of noise ...]

  • If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the namespaces in which its associated classes are defined.

So to summary, we have as associated classes are X<0> and the associated namespaces are the global namespace. Now the friend functions that are visible are

  • Any namespace-scope friend functions declared in associated classes are visible within their respective namespaces even if they are not visible during an ordinary lookup

There is no friend function declared in X<0> so the friend function declaration is not visible when looking into the global namespace. Note that X<0> is an entirely different class-type than X<1>. The implicit instantiation of X<1> you do there has no effect on this call - it just adds a non-visible name into the global namespace that refers to a friend function of class X<1>.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文