C++ 关于C+中自由函数名解析的问题+;模板

C++ 关于C+中自由函数名解析的问题+;模板,c++,templates,C++,Templates,该程序按预期工作: #include <iostream> template <typename T> void output(T t) { prt(t); } struct It { It(int* p) : p(p) {} int* p; }; void prt(It it) { std::cout << *(it.p) << std::endl; } int main() { int val = 12;

该程序按预期工作:

#include <iostream>

template <typename T>
void output(T t) {
   prt(t);
}

struct It {
   It(int* p) : p(p) {}
   int* p;
};

void prt(It it) {
   std::cout << *(it.p) << std::endl;
}

int main() {
   int val = 12;
   It it(&val);
   output(it);    
   return 0;
}

唯一改变的是传递给输出的参数是内置类型,而不是用户定义的类型。但我不认为这会影响名字的解析。所以我的问题是:1)为什么第二个例子失败了?;2)为什么一个例子失败而另一个成功?

这里适用的标准规则如下:

对于后缀表达式为从属名称的函数调用,使用常用的查找规则([basic.lookup.unqual],[basic.lookup.argdep])查找候选函数,但以下情况除外:

  • 对于使用非限定名称查找的查找部分,只找到模板定义上下文中的函数声明

  • 对于使用关联名称空间([basic.lookup.argdep])的查找部分,只能找到在模板定义上下文或模板实例化上下文中找到的函数声明

在这两个示例中,非限定名称查找未找到
prt
的声明,因为在定义模板之前没有此类声明。因此,我们继续进行参数相关的查找,它只在参数类型的相关名称空间中查找

是全局名称空间的成员,因此全局名称空间是一个关联的名称空间,并且该名称空间中的一个声明在模板实例化上下文中可见

指针类型
U*
与类型
U
具有相同的关联命名空间,而基本类型根本没有关联命名空间。因此,由于唯一的参数类型
int*
是指向基本类型的指针,因此没有关联的名称空间,依赖于参数的查找不可能在第二个程序中找到任何声明


我不能确切地说为什么规则是这样设计的,但我猜其目的是模板应该使用它想要使用的特定声明函数,或者使用函数作为可扩展的自定义点,但是这些用户自定义需要与它们将使用的用户定义类型密切相关。否则,就有可能通过为某些特定情况提供更好的重载来更改真正打算使用一个特定函数或函数模板声明的模板的行为。诚然,这更多地是从模板定义上下文中至少有一个声明的角度来看的,而不是当该查找什么也找不到时,但随后我们会遇到SFINAE指望找不到某个东西的情况,等等。

msvc不介意,但clang也失败了。我认为关于::8:6的部分:注意:'void prt(int*)在这里声明,稍后在翻译中声明这很能说明问题——编译器看到了定义,只是选择不使用它。我猜这与ADL以及ADL如何查找内置类型和用户声明的类型有关。这是一个有趣的想法,但我不知道ADL如何在这里发挥作用:在示例中,所有内容都位于同一名称空间中。是的,我想就是这样,谢谢。我在中找到了更多的细节。
#include <iostream>

template <typename T>
void output(T t) {
   prt(t);
}

void prt(int* p) {
   std::cout << (*p) << std::endl;
}

int main() {
   int val = 12;
   output(&val);
   return 0;
}
     'prt' was not declared in this scope, and no declarations were found by
 argument-dependent lookup at the point of instantiation [-fpermissive]