C++ ADL与朋友注射

C++ ADL与朋友注射,c++,templates,friend-function,argument-dependent-lookup,C++,Templates,Friend Function,Argument Dependent Lookup,考虑以下代码: template <int N> struct X { friend void f(X *) {} }; int main() { f((X<0> *)0); // Error? } 模板 结构X { 友元空f(X*){} }; int main() { f((X*)0);//错误? } 编译人员似乎非常不同意。(MSVC08/10表示否,GCC标准在14.7.1/4 如果在需要完全定义的对象类型的上下文中使用类类型,或者如果类类型的完整性影响程

考虑以下代码:

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

int main()
{
 f((X<0> *)0); // Error?
}
模板
结构X
{
友元空f(X*){}
};
int main()
{
f((X*)0);//错误?
}

编译人员似乎非常不同意。(MSVC08/10表示否,GCC标准在
14.7.1/4

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

注意,Vandervoorde提出了一项建议,委员会发现

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

对于第二种情况,需要考虑参数<代码> >(x*)< /C>的相关类和命名空间。因为这是指向类模板特化的指针(注意下面的“模板ID”不正确- C++ +X纠正了使用正确的项),也是指向类的指针。(在C++0x中也纠正了这一令人困惑的拆分-它在一个要点中列出了这两种情况)

  • 如果T是模板id,则其关联的命名空间和类是模板所在的命名空间 定义;[…大量噪音…]

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

总之,我们有as关联的类是
X
,关联的名称空间是全局名称空间

  • 关联类中声明的任何命名空间作用域友元函数在各自的命名空间中都可见,即使它们在普通查找过程中不可见

X
中没有声明友元函数,因此在查看全局命名空间时友元函数声明不可见。请注意,
X
X
是完全不同的类类型。
X
的隐式实例化对该调用没有影响-它只是添加了一个不可见的名称到引用类
X

的友元函数的全局命名空间中,那么第一个示例是否可以编译?谢谢:)这或多或少是我所怀疑的。为什么这么多的编译器把第二种情况弄错了?另外,如果你也能为其他引号引用标准,我会很感激的。@uj2好吧,至少与GCC相比,clang看起来不错。它正确地拒绝了第二种情况。特别是GCC有相当多的模板一致性e的问题,所以这并不让我感到惊讶。你试图找到标准段落的其他引号是什么?@jpalecek是的,第一个例子应该编译。@litb:clang没有通过第一个例子,也没有找到自己是模板的朋友……我指的是最后两个引号:“如果t是模板id…”“任何命名空间范围朋友…”
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?
}