ADL 和友元注入
考虑一下这段代码:
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
标准在
14.7.1/4
中表示请注意,Vandervoorde 在此处发布了问题报告 ,委员会发现
对于第二种情况 - 您需要考虑参数
f(X<0>*)
的关联类和命名空间。这些是,因为这是一个指向类模板专门化的指针(请注意,下面的“template-id”不太正确 - C++0x 更正了它以使用正确的术语),也是一个指向类的指针(这种令人困惑的分割在 C++0x 中也得到了纠正 - 它在一个要点中列出了这两种情况)。总而言之,我们的关联类是
X<0>
,关联的命名空间是全局命名空间。现在可见的友元函数是X<0>
中没有声明友元函数,因此友元函数声明为查看全局命名空间时不可见。请注意,X<0>
是与X<1>
完全不同的类类型。您在那里执行的X<1>
隐式实例化对此调用没有任何影响 - 它只是将一个不可见的名称添加到引用类X<1> 的友元函数的全局命名空间中。 1>
。The Standard says at
14.7.1/4
Note that Vandervoorde made an issue report here, and the committee found
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).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 areThere is no friend function declared in
X<0>
so the friend function declaration is not visible when looking into the global namespace. Note thatX<0>
is an entirely different class-type thanX<1>
. The implicit instantiation ofX<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 classX<1>
.